portkey-admin-mcp 0.11.0 → 0.11.2

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/ENDPOINTS.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Portkey Admin API endpoints and MCP tools
2
2
 
3
3
  Generated from the registered tool catalog by `npm run generate:endpoints`.
4
- Route mappings were reviewed against the official Portkey OpenAPI on 2026-08-27.
4
+ Route mappings were reviewed against the official Portkey OpenAPI on 2026-08-28.
5
5
 
6
6
  - Base URL: `https://api.portkey.ai/v1`
7
7
  - Authentication: `x-portkey-api-key`
@@ -139,7 +139,7 @@ Routes:
139
139
  | `list_virtual_keys` | List provider API keys stored as virtual keys in your Portkey org. Use this to find slugs before wiring prompts/configs or auditing limits. Returns total plus name, slug, status, usage limits, rate limits, reset state, and model config. |
140
140
  | `create_virtual_key` | Store a provider API key as a virtual key. The raw key is encrypted and only returned at creation time, so save the returned slug and use it in prompts/configs. Optional usage and rate limits apply immediately, and the tool returns the new slug. |
141
141
  | `get_virtual_key` | Fetch one virtual key by slug, including metadata, a masked secret, limits, status, and model config. Use this before updating or to inspect the current configuration. |
142
- | `update_virtual_key` | Update a virtual key's name, secret, note, or limits. Rotating the key takes effect immediately, and limit changes apply to downstream prompts and configs using this slug. Returns the updated name, slug, and status. |
142
+ | `update_virtual_key` | Update a virtual key's name, secret, note, or limits. Rotating the key takes effect immediately, and limit changes apply to downstream prompts and configs using this slug. Returns success when Portkey accepts the update. |
143
143
  | `delete_virtual_key` | Delete a virtual key by slug. This is irreversible and will break prompts and configs that reference the slug, so confirm no active dependencies first. Returns success after removal. |
144
144
  | `create_api_key` | Create a Portkey API key for auth. Org keys grant broader access; workspace keys are scoped. WARNING: The key secret is returned ONCE in the tool result and will be visible in MCP transcripts and LLM context — store it securely immediately. Using the key grants access immediately according to its scopes, defaults, and limits. Workspace keys require workspace_id and user keys require user_id. |
145
145
  | `list_api_keys` | List Portkey API keys for auditing access, scopes, defaults, limits, and expiration. Use this for API keys only; use list_virtual_keys for provider keys. Returns total plus id, type, status, workspace/user scope, limits, defaults, alert emails, and creation mode. |
package/build/index.js CHANGED
@@ -124,6 +124,9 @@ async function parseErrorResponse(response) {
124
124
  // src/services/base.service.ts
125
125
  var DEFAULT_BASE_URL = "https://api.portkey.ai/v1";
126
126
  var DEFAULT_PUBLIC_BASE_URL = "https://api.portkey.ai";
127
+ function toV2BaseUrl(baseUrl) {
128
+ return baseUrl.replace(/\/v1$/, "/v2");
129
+ }
127
130
  var MISSING_API_KEY_PLACEHOLDER = "__PORTKEY_API_KEY_NOT_CONFIGURED__";
128
131
  var PRIVATE_BASE_URL_OVERRIDE_HINT = "Set PORTKEY_ALLOW_PRIVATE_BASE_URL=true to allow self-hosted gateways on loopback or private networks.";
129
132
  var INSECURE_HTTP_OVERRIDE_HINT = "Set PORTKEY_ALLOW_INSECURE_HTTP=true only for a trusted self-hosted gateway when TLS is unavailable.";
@@ -248,6 +251,7 @@ function isNoContent(value) {
248
251
  var BaseService = class {
249
252
  apiKey;
250
253
  baseUrl;
254
+ v2BaseUrl;
251
255
  timeout = 3e4;
252
256
  constructor(apiKeyOverride, baseUrlOverride) {
253
257
  const apiKey = apiKeyOverride ?? process.env.PORTKEY_API_KEY;
@@ -258,6 +262,7 @@ var BaseService = class {
258
262
  const baseUrl = baseUrlOverride ?? process.env.PORTKEY_BASE_URL ?? DEFAULT_BASE_URL;
259
263
  validateUrl(baseUrl);
260
264
  this.baseUrl = baseUrl.replace(/\/+$/, "");
265
+ this.v2BaseUrl = toV2BaseUrl(this.baseUrl);
261
266
  }
262
267
  encodePathSegment(value) {
263
268
  return encodeURIComponent(value);
@@ -368,11 +373,38 @@ var BaseService = class {
368
373
  })
369
374
  );
370
375
  }
376
+ /** Read a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
377
+ async getV2(path, params) {
378
+ return this.rejectNoContent(
379
+ await this.executeRequest("GET", path, {
380
+ params,
381
+ baseUrl: this.v2BaseUrl
382
+ })
383
+ );
384
+ }
371
385
  async post(path, body) {
372
386
  return this.rejectNoContent(
373
387
  await this.executeRequest("POST", path, { body })
374
388
  );
375
389
  }
390
+ /** Write to a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
391
+ async postV2(path, body) {
392
+ return this.rejectNoContent(
393
+ await this.executeRequest("POST", path, {
394
+ body,
395
+ baseUrl: this.v2BaseUrl
396
+ })
397
+ );
398
+ }
399
+ /** Update a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
400
+ async putV2(path, body) {
401
+ return this.rejectNoContent(
402
+ await this.executeRequest("PUT", path, {
403
+ body,
404
+ baseUrl: this.v2BaseUrl
405
+ })
406
+ );
407
+ }
376
408
  async put(path, body) {
377
409
  return this.rejectNoContent(
378
410
  await this.executeRequest("PUT", path, { body })
@@ -389,6 +421,14 @@ var BaseService = class {
389
421
  allowNoContent: true
390
422
  });
391
423
  }
424
+ /** Delete on a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
425
+ async deleteV2(path, params) {
426
+ return this.executeRequest("DELETE", path, {
427
+ params,
428
+ allowNoContent: true,
429
+ baseUrl: this.v2BaseUrl
430
+ });
431
+ }
392
432
  };
393
433
 
394
434
  // src/services/analytics.service.ts
@@ -682,28 +722,28 @@ var ConfigsService = class extends BaseService {
682
722
  // src/services/deployments.service.ts
683
723
  var DeploymentsService = class extends BaseService {
684
724
  async listDeployments(params) {
685
- return this.get("/deployments", params);
725
+ return this.getV2("/deployments", params);
686
726
  }
687
727
  async registerDeployment(data) {
688
- return this.post("/deployments", data);
728
+ return this.postV2("/deployments", data);
689
729
  }
690
730
  async getDeployment(id, organisation_id) {
691
731
  if (!id.trim()) throw new Error("Deployment ID is required");
692
- return this.get(
732
+ return this.getV2(
693
733
  `/deployments/${this.encodePathSegment(id)}`,
694
734
  { organisation_id }
695
735
  );
696
736
  }
697
737
  async updateDeployment(id, data) {
698
738
  if (!id.trim()) throw new Error("Deployment ID is required");
699
- return this.put(
739
+ return this.putV2(
700
740
  `/deployments/${this.encodePathSegment(id)}`,
701
741
  data
702
742
  );
703
743
  }
704
744
  async archiveDeployment(id) {
705
745
  if (!id.trim()) throw new Error("Deployment ID is required");
706
- const result = await this.delete(
746
+ const result = await this.deleteV2(
707
747
  `/deployments/${this.encodePathSegment(id)}`
708
748
  );
709
749
  return isNoContent(result) ? {} : result;
@@ -714,13 +754,13 @@ var DeploymentsService = class extends BaseService {
714
754
  var GuardrailsService = class extends BaseService {
715
755
  /** Get the organisation-wide input and output guardrail defaults. */
716
756
  async getOrganisationDefaults() {
717
- return this.get(
757
+ return this.getV2(
718
758
  "/admin/organisation/defaults"
719
759
  );
720
760
  }
721
761
  /** Replace either or both organisation-wide guardrail default lists. */
722
762
  async updateOrganisationDefaults(data) {
723
- return this.put(
763
+ return this.putV2(
724
764
  "/admin/organisation/defaults",
725
765
  data
726
766
  );
@@ -1467,7 +1507,7 @@ var PromptsService = class extends BaseService {
1467
1507
  }
1468
1508
  async findPromptByExactName(name, collectionId) {
1469
1509
  const pageSize = 100;
1470
- let currentPage = 1;
1510
+ let currentPage = 0;
1471
1511
  while (true) {
1472
1512
  const page = await this.listPrompts({
1473
1513
  collection_id: collectionId,
@@ -1481,7 +1521,7 @@ var PromptsService = class extends BaseService {
1481
1521
  if (exact) {
1482
1522
  return exact;
1483
1523
  }
1484
- if (page.data.length === 0 || currentPage * pageSize >= page.total) {
1524
+ if (page.data.length === 0 || (currentPage + 1) * pageSize >= page.total) {
1485
1525
  return void 0;
1486
1526
  }
1487
1527
  currentPage += 1;
@@ -1900,7 +1940,7 @@ var WorkspacesService = class extends BaseService {
1900
1940
  return { success: true };
1901
1941
  }
1902
1942
  async listScimGroups(params) {
1903
- return this.get("/scim/groups", params);
1943
+ return this.getV2("/scim/groups", params);
1904
1944
  }
1905
1945
  async listWorkspaces(params) {
1906
1946
  return this.get("/admin/workspaces", params);
@@ -2195,7 +2235,7 @@ var baseAnalyticsSchema = {
2195
2235
  };
2196
2236
  var paginatedAnalyticsSchema = {
2197
2237
  ...baseAnalyticsSchema,
2198
- current_page: z2.coerce.number().int().nonnegative().optional().describe("Page number for pagination"),
2238
+ current_page: z2.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2199
2239
  page_size: z2.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
2200
2240
  };
2201
2241
  var cacheSummarySchema = {
@@ -2683,7 +2723,7 @@ var AUDIT_TOOL_SCHEMAS = {
2683
2723
  end_time: z3.string().optional().describe(
2684
2724
  "End of time range filter (ISO 8601 format, e.g., '2024-01-31T23:59:59Z')"
2685
2725
  ),
2686
- current_page: z3.coerce.number().int().positive().optional().describe("Page number for pagination (starts at 1)"),
2726
+ current_page: z3.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2687
2727
  page_size: z3.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
2688
2728
  }
2689
2729
  };
@@ -2735,7 +2775,7 @@ var COLLECTIONS_TOOL_SCHEMAS = {
2735
2775
  listCollections: {
2736
2776
  workspace_id: z4.string().optional().describe("Filter by workspace ID"),
2737
2777
  search: z4.string().optional().describe("Search collections by name"),
2738
- current_page: z4.coerce.number().int().positive().optional().describe("Page number for pagination"),
2778
+ current_page: z4.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2739
2779
  page_size: z4.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
2740
2780
  },
2741
2781
  createCollection: {
@@ -2848,7 +2888,7 @@ var configTargetSchema = z5.object({
2848
2888
  });
2849
2889
  var CONFIGS_TOOL_SCHEMAS = {
2850
2890
  listConfigs: {
2851
- current_page: z5.coerce.number().int().positive().optional().describe("Page number for pagination"),
2891
+ current_page: z5.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2852
2892
  page_size: z5.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
2853
2893
  },
2854
2894
  getConfig: {
@@ -3248,7 +3288,7 @@ var GUARDRAILS_TOOL_SCHEMAS = {
3248
3288
  workspace_id: z7.string().optional().describe("Filter guardrails by workspace ID"),
3249
3289
  organisation_id: z7.string().optional().describe("Filter guardrails by organization ID"),
3250
3290
  page_size: z7.coerce.number().int().min(1).max(100).optional().describe("Number of items per page (1-100, default: 100)"),
3251
- current_page: z7.coerce.number().int().nonnegative().optional().describe("Page number for pagination")
3291
+ current_page: z7.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0")
3252
3292
  },
3253
3293
  getGuardrail: {
3254
3294
  guardrail_id: z7.string().describe("The guardrail UUID or slug (with guard_ prefix) to retrieve")
@@ -3648,7 +3688,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3648
3688
  model: z9.string().describe("Exact provider model identifier, such as gpt-4o")
3649
3689
  },
3650
3690
  listIntegrations: {
3651
- current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
3691
+ current_page: z9.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
3652
3692
  page_size: z9.coerce.number().int().positive().max(100).optional().describe("Number of results per page (default 100, max 100)"),
3653
3693
  workspace_id: z9.string().optional().describe("Filter integrations accessible by a specific workspace"),
3654
3694
  type: z9.enum(["workspace", "organisation", "all"]).optional().describe(
@@ -3715,7 +3755,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3715
3755
  },
3716
3756
  listIntegrationModels: {
3717
3757
  slug: z9.string().describe("The slug of the integration"),
3718
- current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
3758
+ current_page: z9.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
3719
3759
  page_size: z9.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3720
3760
  },
3721
3761
  updateIntegrationModels: {
@@ -3744,7 +3784,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3744
3784
  },
3745
3785
  listIntegrationWorkspaces: {
3746
3786
  slug: z9.string().describe("The slug of the integration"),
3747
- current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
3787
+ current_page: z9.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
3748
3788
  page_size: z9.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3749
3789
  },
3750
3790
  updateIntegrationWorkspaces: {
@@ -4150,7 +4190,7 @@ var rotationPolicySchema = z10.object({
4150
4190
  }).describe("Automatic API-key rotation policy, or null to remove it");
4151
4191
  var KEYS_TOOL_SCHEMAS = {
4152
4192
  listVirtualKeys: {
4153
- current_page: z10.coerce.number().int().positive().optional().describe("Page number for pagination"),
4193
+ current_page: z10.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
4154
4194
  page_size: z10.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
4155
4195
  },
4156
4196
  createVirtualKey: {
@@ -4220,7 +4260,7 @@ var KEYS_TOOL_SCHEMAS = {
4220
4260
  },
4221
4261
  listApiKeys: {
4222
4262
  page_size: z10.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
4223
- current_page: z10.coerce.number().int().positive().optional().describe("Page number for pagination"),
4263
+ current_page: z10.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
4224
4264
  workspace_id: z10.string().optional().describe("Filter by workspace ID")
4225
4265
  },
4226
4266
  getApiKey: {
@@ -4612,7 +4652,7 @@ var LABELS_TOOL_SCHEMAS = {
4612
4652
  organisation_id: z11.string().optional().describe("Filter by organisation ID"),
4613
4653
  workspace_id: z11.string().optional().describe("Filter by workspace ID"),
4614
4654
  search: z11.string().optional().describe("Search labels by name"),
4615
- current_page: z11.coerce.number().int().positive().optional().describe("Page number for pagination"),
4655
+ current_page: z11.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
4616
4656
  page_size: z11.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
4617
4657
  },
4618
4658
  getPromptLabel: {
@@ -5309,7 +5349,7 @@ var mcpConfigurationsSchema = z14.record(z14.string(), z14.unknown()).superRefin
5309
5349
  });
5310
5350
  var MCP_INTEGRATIONS_TOOL_SCHEMAS = {
5311
5351
  listMcpIntegrations: {
5312
- current_page: z14.coerce.number().int().nonnegative().optional().describe("Page number for pagination"),
5352
+ current_page: z14.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5313
5353
  page_size: z14.coerce.number().int().positive().max(1e3).optional().describe("Number of results per page (max 1000)"),
5314
5354
  workspace_id: z14.string().optional().describe("Filter by workspace ID"),
5315
5355
  organisation_id: z14.string().optional().describe("Filter by organisation UUID"),
@@ -5650,7 +5690,7 @@ function registerMcpIntegrationsTools(server, service) {
5650
5690
  import { z as z15 } from "zod";
5651
5691
  var MCP_SERVERS_TOOL_SCHEMAS = {
5652
5692
  listMcpServers: {
5653
- current_page: z15.coerce.number().int().positive().optional().describe("Page number for pagination"),
5693
+ current_page: z15.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5654
5694
  page_size: z15.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
5655
5695
  workspace_id: z15.string().optional().describe("Filter by workspace ID")
5656
5696
  },
@@ -5676,7 +5716,7 @@ var MCP_SERVERS_TOOL_SCHEMAS = {
5676
5716
  },
5677
5717
  listMcpServerCapabilities: {
5678
5718
  id: z15.string().describe("The MCP server ID or slug"),
5679
- current_page: z15.coerce.number().int().positive().optional().describe("Page number for pagination"),
5719
+ current_page: z15.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5680
5720
  page_size: z15.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
5681
5721
  },
5682
5722
  updateMcpServerCapabilities: {
@@ -5691,7 +5731,7 @@ var MCP_SERVERS_TOOL_SCHEMAS = {
5691
5731
  },
5692
5732
  listMcpServerUserAccess: {
5693
5733
  id: z15.string().describe("The MCP server ID or slug"),
5694
- current_page: z15.coerce.number().int().positive().optional().describe("Page number for pagination"),
5734
+ current_page: z15.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5695
5735
  page_size: z15.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
5696
5736
  },
5697
5737
  updateMcpServerUserAccess: {
@@ -6234,7 +6274,7 @@ var PROMPTS_TOOL_SCHEMAS = {
6234
6274
  ),
6235
6275
  workspace_id: z18.string().optional().describe("Filter by workspace ID"),
6236
6276
  search: z18.string().optional().describe("Search prompts by name"),
6237
- current_page: z18.coerce.number().int().positive().optional().describe("Page number for pagination"),
6277
+ current_page: z18.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
6238
6278
  page_size: z18.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
6239
6279
  },
6240
6280
  getPrompt: {
@@ -6410,11 +6450,12 @@ function formatPromptVersion(version) {
6410
6450
  };
6411
6451
  }
6412
6452
  function formatPromptListResponse(prompts, params) {
6413
- const currentPage = params.current_page ?? 1;
6453
+ const paginated = params.current_page !== void 0;
6454
+ const currentPage = params.current_page ?? 0;
6414
6455
  const returnedCount = prompts.data.length;
6415
6456
  const pageSize = params.page_size ?? returnedCount;
6416
- const nextOffset = currentPage * pageSize;
6417
- const hasMore = returnedCount > 0 && nextOffset < prompts.total;
6457
+ const nextOffset = (currentPage + 1) * pageSize;
6458
+ const hasMore = paginated && returnedCount > 0 && nextOffset < prompts.total;
6418
6459
  return {
6419
6460
  total: prompts.total,
6420
6461
  current_page: currentPage,
@@ -6815,7 +6856,7 @@ function registerPromptsTools(server, service) {
6815
6856
  import { z as z19 } from "zod";
6816
6857
  var PROVIDERS_TOOL_SCHEMAS = {
6817
6858
  listProviders: {
6818
- current_page: z19.coerce.number().int().positive().optional().describe("Page number for pagination"),
6859
+ current_page: z19.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
6819
6860
  page_size: z19.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100, default 50)"),
6820
6861
  workspace_id: z19.string().optional().describe(
6821
6862
  "Workspace ID - required when using organization admin keys, optional with workspace API keys"
@@ -7449,7 +7490,7 @@ function registerTracingTools(server, service) {
7449
7490
  import { z as z22 } from "zod";
7450
7491
  var USERS_TOOL_SCHEMAS = {
7451
7492
  listAllUsers: {
7452
- current_page: z22.coerce.number().int().nonnegative().optional().describe("Page number for pagination"),
7493
+ current_page: z22.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
7453
7494
  page_size: z22.coerce.number().int().nonnegative().max(100).optional().describe("Number of results per page (max 100)"),
7454
7495
  role: z22.enum(["admin", "member", "owner"]).optional().describe("Filter by organisation role"),
7455
7496
  email: z22.string().email().optional().describe("Filter by exact email")
@@ -7508,7 +7549,7 @@ var USERS_TOOL_SCHEMAS = {
7508
7549
  user_id: z22.string().describe("The user ID to delete")
7509
7550
  },
7510
7551
  listUserInvites: {
7511
- current_page: z22.coerce.number().int().positive().optional().describe("Page number for pagination"),
7552
+ current_page: z22.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
7512
7553
  page_size: z22.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
7513
7554
  role: z22.enum(["admin", "member"]).optional().describe("Filter invitations by organisation role"),
7514
7555
  email: z22.string().email().optional().describe("Filter by invited email"),
@@ -7721,7 +7762,7 @@ var createScimWorkspaceMappingSchema = z23.object(createScimWorkspaceMappingShap
7721
7762
  var WORKSPACES_TOOL_SCHEMAS = {
7722
7763
  listWorkspaces: {
7723
7764
  page_size: z23.coerce.number().int().positive().max(100).optional().describe("Number of workspaces to return per page (max 100)"),
7724
- current_page: z23.coerce.number().int().nonnegative().optional().describe("Page number to retrieve when results are paginated"),
7765
+ current_page: z23.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
7725
7766
  name: z23.string().optional().describe("Case-sensitive name filter"),
7726
7767
  exact_name: z23.string().optional().describe("Exact workspace name filter"),
7727
7768
  status: z23.enum(["active", "archived"]).optional().describe("Filter by workspace lifecycle status")
package/build/server.js CHANGED
@@ -141,6 +141,9 @@ var Logger = {
141
141
  // src/services/base.service.ts
142
142
  var DEFAULT_BASE_URL = "https://api.portkey.ai/v1";
143
143
  var DEFAULT_PUBLIC_BASE_URL = "https://api.portkey.ai";
144
+ function toV2BaseUrl(baseUrl) {
145
+ return baseUrl.replace(/\/v1$/, "/v2");
146
+ }
144
147
  var MISSING_API_KEY_PLACEHOLDER = "__PORTKEY_API_KEY_NOT_CONFIGURED__";
145
148
  var PRIVATE_BASE_URL_OVERRIDE_HINT = "Set PORTKEY_ALLOW_PRIVATE_BASE_URL=true to allow self-hosted gateways on loopback or private networks.";
146
149
  var INSECURE_HTTP_OVERRIDE_HINT = "Set PORTKEY_ALLOW_INSECURE_HTTP=true only for a trusted self-hosted gateway when TLS is unavailable.";
@@ -265,6 +268,7 @@ function isNoContent(value) {
265
268
  var BaseService = class {
266
269
  apiKey;
267
270
  baseUrl;
271
+ v2BaseUrl;
268
272
  timeout = 3e4;
269
273
  constructor(apiKeyOverride, baseUrlOverride) {
270
274
  const apiKey = apiKeyOverride ?? process.env.PORTKEY_API_KEY;
@@ -275,6 +279,7 @@ var BaseService = class {
275
279
  const baseUrl = baseUrlOverride ?? process.env.PORTKEY_BASE_URL ?? DEFAULT_BASE_URL;
276
280
  validateUrl(baseUrl);
277
281
  this.baseUrl = baseUrl.replace(/\/+$/, "");
282
+ this.v2BaseUrl = toV2BaseUrl(this.baseUrl);
278
283
  }
279
284
  encodePathSegment(value) {
280
285
  return encodeURIComponent(value);
@@ -385,11 +390,38 @@ var BaseService = class {
385
390
  })
386
391
  );
387
392
  }
393
+ /** Read a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
394
+ async getV2(path, params) {
395
+ return this.rejectNoContent(
396
+ await this.executeRequest("GET", path, {
397
+ params,
398
+ baseUrl: this.v2BaseUrl
399
+ })
400
+ );
401
+ }
388
402
  async post(path, body) {
389
403
  return this.rejectNoContent(
390
404
  await this.executeRequest("POST", path, { body })
391
405
  );
392
406
  }
407
+ /** Write to a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
408
+ async postV2(path, body) {
409
+ return this.rejectNoContent(
410
+ await this.executeRequest("POST", path, {
411
+ body,
412
+ baseUrl: this.v2BaseUrl
413
+ })
414
+ );
415
+ }
416
+ /** Update a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
417
+ async putV2(path, body) {
418
+ return this.rejectNoContent(
419
+ await this.executeRequest("PUT", path, {
420
+ body,
421
+ baseUrl: this.v2BaseUrl
422
+ })
423
+ );
424
+ }
393
425
  async put(path, body) {
394
426
  return this.rejectNoContent(
395
427
  await this.executeRequest("PUT", path, { body })
@@ -406,6 +438,14 @@ var BaseService = class {
406
438
  allowNoContent: true
407
439
  });
408
440
  }
441
+ /** Delete on a `/v2`-only admin endpoint. See {@link toV2BaseUrl}. */
442
+ async deleteV2(path, params) {
443
+ return this.executeRequest("DELETE", path, {
444
+ params,
445
+ allowNoContent: true,
446
+ baseUrl: this.v2BaseUrl
447
+ });
448
+ }
409
449
  };
410
450
 
411
451
  // src/services/analytics.service.ts
@@ -699,28 +739,28 @@ var ConfigsService = class extends BaseService {
699
739
  // src/services/deployments.service.ts
700
740
  var DeploymentsService = class extends BaseService {
701
741
  async listDeployments(params) {
702
- return this.get("/deployments", params);
742
+ return this.getV2("/deployments", params);
703
743
  }
704
744
  async registerDeployment(data) {
705
- return this.post("/deployments", data);
745
+ return this.postV2("/deployments", data);
706
746
  }
707
747
  async getDeployment(id, organisation_id) {
708
748
  if (!id.trim()) throw new Error("Deployment ID is required");
709
- return this.get(
749
+ return this.getV2(
710
750
  `/deployments/${this.encodePathSegment(id)}`,
711
751
  { organisation_id }
712
752
  );
713
753
  }
714
754
  async updateDeployment(id, data) {
715
755
  if (!id.trim()) throw new Error("Deployment ID is required");
716
- return this.put(
756
+ return this.putV2(
717
757
  `/deployments/${this.encodePathSegment(id)}`,
718
758
  data
719
759
  );
720
760
  }
721
761
  async archiveDeployment(id) {
722
762
  if (!id.trim()) throw new Error("Deployment ID is required");
723
- const result = await this.delete(
763
+ const result = await this.deleteV2(
724
764
  `/deployments/${this.encodePathSegment(id)}`
725
765
  );
726
766
  return isNoContent(result) ? {} : result;
@@ -731,13 +771,13 @@ var DeploymentsService = class extends BaseService {
731
771
  var GuardrailsService = class extends BaseService {
732
772
  /** Get the organisation-wide input and output guardrail defaults. */
733
773
  async getOrganisationDefaults() {
734
- return this.get(
774
+ return this.getV2(
735
775
  "/admin/organisation/defaults"
736
776
  );
737
777
  }
738
778
  /** Replace either or both organisation-wide guardrail default lists. */
739
779
  async updateOrganisationDefaults(data) {
740
- return this.put(
780
+ return this.putV2(
741
781
  "/admin/organisation/defaults",
742
782
  data
743
783
  );
@@ -1484,7 +1524,7 @@ var PromptsService = class extends BaseService {
1484
1524
  }
1485
1525
  async findPromptByExactName(name, collectionId) {
1486
1526
  const pageSize = 100;
1487
- let currentPage = 1;
1527
+ let currentPage = 0;
1488
1528
  while (true) {
1489
1529
  const page = await this.listPrompts({
1490
1530
  collection_id: collectionId,
@@ -1498,7 +1538,7 @@ var PromptsService = class extends BaseService {
1498
1538
  if (exact) {
1499
1539
  return exact;
1500
1540
  }
1501
- if (page.data.length === 0 || currentPage * pageSize >= page.total) {
1541
+ if (page.data.length === 0 || (currentPage + 1) * pageSize >= page.total) {
1502
1542
  return void 0;
1503
1543
  }
1504
1544
  currentPage += 1;
@@ -1917,7 +1957,7 @@ var WorkspacesService = class extends BaseService {
1917
1957
  return { success: true };
1918
1958
  }
1919
1959
  async listScimGroups(params) {
1920
- return this.get("/scim/groups", params);
1960
+ return this.getV2("/scim/groups", params);
1921
1961
  }
1922
1962
  async listWorkspaces(params) {
1923
1963
  return this.get("/admin/workspaces", params);
@@ -2212,7 +2252,7 @@ var baseAnalyticsSchema = {
2212
2252
  };
2213
2253
  var paginatedAnalyticsSchema = {
2214
2254
  ...baseAnalyticsSchema,
2215
- current_page: z2.coerce.number().int().nonnegative().optional().describe("Page number for pagination"),
2255
+ current_page: z2.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2216
2256
  page_size: z2.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
2217
2257
  };
2218
2258
  var cacheSummarySchema = {
@@ -2700,7 +2740,7 @@ var AUDIT_TOOL_SCHEMAS = {
2700
2740
  end_time: z3.string().optional().describe(
2701
2741
  "End of time range filter (ISO 8601 format, e.g., '2024-01-31T23:59:59Z')"
2702
2742
  ),
2703
- current_page: z3.coerce.number().int().positive().optional().describe("Page number for pagination (starts at 1)"),
2743
+ current_page: z3.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2704
2744
  page_size: z3.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
2705
2745
  }
2706
2746
  };
@@ -2752,7 +2792,7 @@ var COLLECTIONS_TOOL_SCHEMAS = {
2752
2792
  listCollections: {
2753
2793
  workspace_id: z4.string().optional().describe("Filter by workspace ID"),
2754
2794
  search: z4.string().optional().describe("Search collections by name"),
2755
- current_page: z4.coerce.number().int().positive().optional().describe("Page number for pagination"),
2795
+ current_page: z4.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2756
2796
  page_size: z4.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
2757
2797
  },
2758
2798
  createCollection: {
@@ -2865,7 +2905,7 @@ var configTargetSchema = z5.object({
2865
2905
  });
2866
2906
  var CONFIGS_TOOL_SCHEMAS = {
2867
2907
  listConfigs: {
2868
- current_page: z5.coerce.number().int().positive().optional().describe("Page number for pagination"),
2908
+ current_page: z5.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
2869
2909
  page_size: z5.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
2870
2910
  },
2871
2911
  getConfig: {
@@ -3265,7 +3305,7 @@ var GUARDRAILS_TOOL_SCHEMAS = {
3265
3305
  workspace_id: z7.string().optional().describe("Filter guardrails by workspace ID"),
3266
3306
  organisation_id: z7.string().optional().describe("Filter guardrails by organization ID"),
3267
3307
  page_size: z7.coerce.number().int().min(1).max(100).optional().describe("Number of items per page (1-100, default: 100)"),
3268
- current_page: z7.coerce.number().int().nonnegative().optional().describe("Page number for pagination")
3308
+ current_page: z7.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0")
3269
3309
  },
3270
3310
  getGuardrail: {
3271
3311
  guardrail_id: z7.string().describe("The guardrail UUID or slug (with guard_ prefix) to retrieve")
@@ -3665,7 +3705,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3665
3705
  model: z9.string().describe("Exact provider model identifier, such as gpt-4o")
3666
3706
  },
3667
3707
  listIntegrations: {
3668
- current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
3708
+ current_page: z9.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
3669
3709
  page_size: z9.coerce.number().int().positive().max(100).optional().describe("Number of results per page (default 100, max 100)"),
3670
3710
  workspace_id: z9.string().optional().describe("Filter integrations accessible by a specific workspace"),
3671
3711
  type: z9.enum(["workspace", "organisation", "all"]).optional().describe(
@@ -3732,7 +3772,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3732
3772
  },
3733
3773
  listIntegrationModels: {
3734
3774
  slug: z9.string().describe("The slug of the integration"),
3735
- current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
3775
+ current_page: z9.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
3736
3776
  page_size: z9.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3737
3777
  },
3738
3778
  updateIntegrationModels: {
@@ -3761,7 +3801,7 @@ var INTEGRATIONS_TOOL_SCHEMAS = {
3761
3801
  },
3762
3802
  listIntegrationWorkspaces: {
3763
3803
  slug: z9.string().describe("The slug of the integration"),
3764
- current_page: z9.coerce.number().int().positive().optional().describe("Page number for pagination"),
3804
+ current_page: z9.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
3765
3805
  page_size: z9.coerce.number().int().positive().max(100).optional().describe("Number of results per page")
3766
3806
  },
3767
3807
  updateIntegrationWorkspaces: {
@@ -4167,7 +4207,7 @@ var rotationPolicySchema = z10.object({
4167
4207
  }).describe("Automatic API-key rotation policy, or null to remove it");
4168
4208
  var KEYS_TOOL_SCHEMAS = {
4169
4209
  listVirtualKeys: {
4170
- current_page: z10.coerce.number().int().positive().optional().describe("Page number for pagination"),
4210
+ current_page: z10.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
4171
4211
  page_size: z10.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
4172
4212
  },
4173
4213
  createVirtualKey: {
@@ -4237,7 +4277,7 @@ var KEYS_TOOL_SCHEMAS = {
4237
4277
  },
4238
4278
  listApiKeys: {
4239
4279
  page_size: z10.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
4240
- current_page: z10.coerce.number().int().positive().optional().describe("Page number for pagination"),
4280
+ current_page: z10.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
4241
4281
  workspace_id: z10.string().optional().describe("Filter by workspace ID")
4242
4282
  },
4243
4283
  getApiKey: {
@@ -4629,7 +4669,7 @@ var LABELS_TOOL_SCHEMAS = {
4629
4669
  organisation_id: z11.string().optional().describe("Filter by organisation ID"),
4630
4670
  workspace_id: z11.string().optional().describe("Filter by workspace ID"),
4631
4671
  search: z11.string().optional().describe("Search labels by name"),
4632
- current_page: z11.coerce.number().int().positive().optional().describe("Page number for pagination"),
4672
+ current_page: z11.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
4633
4673
  page_size: z11.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
4634
4674
  },
4635
4675
  getPromptLabel: {
@@ -5326,7 +5366,7 @@ var mcpConfigurationsSchema = z14.record(z14.string(), z14.unknown()).superRefin
5326
5366
  });
5327
5367
  var MCP_INTEGRATIONS_TOOL_SCHEMAS = {
5328
5368
  listMcpIntegrations: {
5329
- current_page: z14.coerce.number().int().nonnegative().optional().describe("Page number for pagination"),
5369
+ current_page: z14.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5330
5370
  page_size: z14.coerce.number().int().positive().max(1e3).optional().describe("Number of results per page (max 1000)"),
5331
5371
  workspace_id: z14.string().optional().describe("Filter by workspace ID"),
5332
5372
  organisation_id: z14.string().optional().describe("Filter by organisation UUID"),
@@ -5667,7 +5707,7 @@ function registerMcpIntegrationsTools(server, service) {
5667
5707
  import { z as z15 } from "zod";
5668
5708
  var MCP_SERVERS_TOOL_SCHEMAS = {
5669
5709
  listMcpServers: {
5670
- current_page: z15.coerce.number().int().positive().optional().describe("Page number for pagination"),
5710
+ current_page: z15.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5671
5711
  page_size: z15.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
5672
5712
  workspace_id: z15.string().optional().describe("Filter by workspace ID")
5673
5713
  },
@@ -5693,7 +5733,7 @@ var MCP_SERVERS_TOOL_SCHEMAS = {
5693
5733
  },
5694
5734
  listMcpServerCapabilities: {
5695
5735
  id: z15.string().describe("The MCP server ID or slug"),
5696
- current_page: z15.coerce.number().int().positive().optional().describe("Page number for pagination"),
5736
+ current_page: z15.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5697
5737
  page_size: z15.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
5698
5738
  },
5699
5739
  updateMcpServerCapabilities: {
@@ -5708,7 +5748,7 @@ var MCP_SERVERS_TOOL_SCHEMAS = {
5708
5748
  },
5709
5749
  listMcpServerUserAccess: {
5710
5750
  id: z15.string().describe("The MCP server ID or slug"),
5711
- current_page: z15.coerce.number().int().positive().optional().describe("Page number for pagination"),
5751
+ current_page: z15.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
5712
5752
  page_size: z15.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)")
5713
5753
  },
5714
5754
  updateMcpServerUserAccess: {
@@ -6251,7 +6291,7 @@ var PROMPTS_TOOL_SCHEMAS = {
6251
6291
  ),
6252
6292
  workspace_id: z18.string().optional().describe("Filter by workspace ID"),
6253
6293
  search: z18.string().optional().describe("Search prompts by name"),
6254
- current_page: z18.coerce.number().int().positive().optional().describe("Page number for pagination"),
6294
+ current_page: z18.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
6255
6295
  page_size: z18.coerce.number().int().positive().max(100).optional().describe("Results per page (max 100)")
6256
6296
  },
6257
6297
  getPrompt: {
@@ -6427,11 +6467,12 @@ function formatPromptVersion(version) {
6427
6467
  };
6428
6468
  }
6429
6469
  function formatPromptListResponse(prompts, params) {
6430
- const currentPage = params.current_page ?? 1;
6470
+ const paginated = params.current_page !== void 0;
6471
+ const currentPage = params.current_page ?? 0;
6431
6472
  const returnedCount = prompts.data.length;
6432
6473
  const pageSize = params.page_size ?? returnedCount;
6433
- const nextOffset = currentPage * pageSize;
6434
- const hasMore = returnedCount > 0 && nextOffset < prompts.total;
6474
+ const nextOffset = (currentPage + 1) * pageSize;
6475
+ const hasMore = paginated && returnedCount > 0 && nextOffset < prompts.total;
6435
6476
  return {
6436
6477
  total: prompts.total,
6437
6478
  current_page: currentPage,
@@ -6832,7 +6873,7 @@ function registerPromptsTools(server, service) {
6832
6873
  import { z as z19 } from "zod";
6833
6874
  var PROVIDERS_TOOL_SCHEMAS = {
6834
6875
  listProviders: {
6835
- current_page: z19.coerce.number().int().positive().optional().describe("Page number for pagination"),
6876
+ current_page: z19.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
6836
6877
  page_size: z19.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100, default 50)"),
6837
6878
  workspace_id: z19.string().optional().describe(
6838
6879
  "Workspace ID - required when using organization admin keys, optional with workspace API keys"
@@ -7466,7 +7507,7 @@ function registerTracingTools(server, service) {
7466
7507
  import { z as z22 } from "zod";
7467
7508
  var USERS_TOOL_SCHEMAS = {
7468
7509
  listAllUsers: {
7469
- current_page: z22.coerce.number().int().nonnegative().optional().describe("Page number for pagination"),
7510
+ current_page: z22.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
7470
7511
  page_size: z22.coerce.number().int().nonnegative().max(100).optional().describe("Number of results per page (max 100)"),
7471
7512
  role: z22.enum(["admin", "member", "owner"]).optional().describe("Filter by organisation role"),
7472
7513
  email: z22.string().email().optional().describe("Filter by exact email")
@@ -7525,7 +7566,7 @@ var USERS_TOOL_SCHEMAS = {
7525
7566
  user_id: z22.string().describe("The user ID to delete")
7526
7567
  },
7527
7568
  listUserInvites: {
7528
- current_page: z22.coerce.number().int().positive().optional().describe("Page number for pagination"),
7569
+ current_page: z22.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
7529
7570
  page_size: z22.coerce.number().int().positive().max(100).optional().describe("Number of results per page (max 100)"),
7530
7571
  role: z22.enum(["admin", "member"]).optional().describe("Filter invitations by organisation role"),
7531
7572
  email: z22.string().email().optional().describe("Filter by invited email"),
@@ -7738,7 +7779,7 @@ var createScimWorkspaceMappingSchema = z23.object(createScimWorkspaceMappingShap
7738
7779
  var WORKSPACES_TOOL_SCHEMAS = {
7739
7780
  listWorkspaces: {
7740
7781
  page_size: z23.coerce.number().int().positive().max(100).optional().describe("Number of workspaces to return per page (max 100)"),
7741
- current_page: z23.coerce.number().int().nonnegative().optional().describe("Page number to retrieve when results are paginated"),
7782
+ current_page: z23.coerce.number().int().nonnegative().optional().describe("Zero-based page number; the first page is 0"),
7742
7783
  name: z23.string().optional().describe("Case-sensitive name filter"),
7743
7784
  exact_name: z23.string().optional().describe("Exact workspace name filter"),
7744
7785
  status: z23.enum(["active", "archived"]).optional().describe("Filter by workspace lifecycle status")
@@ -1,6 +1,6 @@
1
1
  # Prisma AIRS interoperability
2
2
 
3
- Last verified: 2026-08-27
3
+ Last verified: 2026-08-28
4
4
 
5
5
  ## Short answer
6
6
 
@@ -19,6 +19,10 @@ Changing `PORTKEY_BASE_URL` to a Prisma AIRS or Strata Cloud Manager URL will no
19
19
 
20
20
  Palo Alto Networks says the Portkey acquisition makes Portkey the core AI Gateway for Prisma AIRS. Its current AI Gateway instructions direct administrators to Strata Cloud Manager, while the documented Prisma AIRS MCP endpoint is for centralized AI-agent security. No public Prisma AIRS admin contract equivalent to Portkey's users, workspaces, prompts, configs, integrations, or keys is documented today. That last sentence is an inference from the currently published product and API documentation, not a promise that such an API will never exist.
21
21
 
22
+ The August 2026 Prisma AIRS additions cover runtime, model, skill, discovery, and
23
+ red-team security capabilities. They do not publish a Portkey-compatible AI
24
+ Gateway administration contract, so they do not change this boundary.
25
+
22
26
  ## Recommended coexistence
23
27
 
24
28
  Run the two MCP servers side by side when you need both administration and runtime security:
package/package.json CHANGED
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "name": "portkey-admin-mcp",
58
58
  "mcpName": "io.github.CodesWhat/portkey-admin-mcp",
59
- "version": "0.11.0",
59
+ "version": "0.11.2",
60
60
  "main": "build/index.js",
61
61
  "keywords": [
62
62
  "mcp",