@promptlayer/mcp-server 1.10.0 → 1.13.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/gcp/src/index.ts CHANGED
@@ -32,12 +32,15 @@ const TOOL_HANDLERS: Record<string, ToolHandler> = {
32
32
  c.deletePromptLabel(prompt_label_id as number),
33
33
  "get-snippet-usage": (c, { api_key: _, identifier, ...p }) =>
34
34
  c.getSnippetUsage(identifier as string, p),
35
+ "patch-prompt-template-version": (c, { api_key: _, identifier, ...b }) =>
36
+ c.patchPromptTemplateVersion(identifier as string, b),
35
37
 
36
38
  // Request Logs
37
39
  "search-request-logs": (c, a) => c.searchRequestLogs(body(a)),
38
40
  "get-request": (c, { request_id }) => c.getRequest(request_id as number),
39
41
  "get-trace": (c, { trace_id }) => c.getTrace(trace_id as string),
40
42
  "get-request-search-suggestions": (c, a) => c.getRequestSearchSuggestions(body(a)),
43
+ "get-request-analytics": (c, a) => c.getRequestAnalytics(body(a)),
41
44
 
42
45
  // Tracking
43
46
  "log-request": (c, a) => c.logRequest(body(a)),
@@ -52,6 +55,7 @@ const TOOL_HANDLERS: Record<string, ToolHandler> = {
52
55
  c.getDatasetRows(dataset_id as number, p),
53
56
  "create-draft-dataset-version": (c, a) => c.createDraftDatasetVersion(body(a)),
54
57
  "add-request-log-to-dataset": (c, a) => c.addRequestLogToDatasetVersion(body(a)),
58
+ "add-trace-to-dataset": (c, a) => c.addTraceToDatasetVersion(body(a)),
55
59
  "save-draft-dataset-version": (c, a) => c.saveDraftDatasetVersion(body(a)),
56
60
 
57
61
  // Evaluations
@@ -97,6 +101,12 @@ const TOOL_HANDLERS: Record<string, ToolHandler> = {
97
101
  "create-tool-registry": (c, a) => c.createToolRegistry(body(a)),
98
102
  "create-tool-version": (c, { api_key: _, identifier, ...b }) =>
99
103
  c.createToolVersion(identifier as string, b),
104
+ "test-execute-tool-registry": (c, { api_key: _, identifier, label, version, ...b }) => {
105
+ const query: Args = {};
106
+ if (label !== undefined) query.label = label;
107
+ if (version !== undefined) query.version = version;
108
+ return c.testExecuteToolRegistry(identifier as string, b, query);
109
+ },
100
110
 
101
111
  // Folders
102
112
  "create-folder": (c, a) => c.createFolder(body(a)),
@@ -106,6 +116,16 @@ const TOOL_HANDLERS: Record<string, ToolHandler> = {
106
116
  "move-folder-entities": (c, a) => c.moveFolderEntities(body(a)),
107
117
  "delete-folder-entities": (c, a) => c.deleteFolderEntities(body(a)),
108
118
  "resolve-folder-id": (c, a) => c.resolveFolderId(body(a)),
119
+
120
+ // Skill Collections
121
+ "list-skill-collections": (c) => c.listSkillCollections(),
122
+ "create-skill-collection": (c, a) => c.createSkillCollection(body(a)),
123
+ "get-skill-collection": (c, { api_key: _, identifier, ...p }) =>
124
+ c.getSkillCollection(identifier as string, p),
125
+ "update-skill-collection": (c, { api_key: _, identifier, ...b }) =>
126
+ c.updateSkillCollection(identifier as string, b),
127
+ "save-skill-collection-version": (c, { api_key: _, identifier, ...b }) =>
128
+ c.saveSkillCollectionVersion(identifier as string, b),
109
129
  };
110
130
 
111
131
  // ── Instructions ────────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptlayer/mcp-server",
3
- "version": "1.10.0",
3
+ "version": "1.13.0",
4
4
  "description": "Model Context Protocol server for PromptLayer",
5
5
  "type": "module",
6
6
  "main": "build/index.js",
@@ -34,11 +34,13 @@
34
34
  "node": ">=18.0.0"
35
35
  },
36
36
  "overrides": {
37
- "hono": "^4.12.14",
37
+ "hono": "^4.12.18",
38
38
  "@hono/node-server": "^1.19.13",
39
39
  "express-rate-limit": "^8.2.2",
40
40
  "path-to-regexp": "^8.4.0",
41
- "qs": "^6.14.2",
42
- "ajv": "^8.18.0"
41
+ "qs": "^6.15.2",
42
+ "ajv": "^8.18.0",
43
+ "fast-uri": "^3.1.2",
44
+ "ip-address": "^10.1.1"
43
45
  }
44
46
  }
package/src/client.ts CHANGED
@@ -73,6 +73,7 @@ export class PromptLayerClient {
73
73
  createDatasetVersionFromFilterParams(body: Body) { return this.post("/api/public/v2/dataset-versions/from-filter-params", body); }
74
74
  createDraftDatasetVersion(body: Body) { return this.post("/api/public/v2/dataset-versions/create-draft", body); }
75
75
  addRequestLogToDatasetVersion(body: Body) { return this.post("/api/public/v2/dataset-versions/add-request-log", body); }
76
+ addTraceToDatasetVersion(body: Body) { return this.post("/api/public/v2/dataset-versions/add-trace", body); }
76
77
  saveDraftDatasetVersion(body: Body) { return this.post("/api/public/v2/dataset-versions/save-draft", body); }
77
78
 
78
79
  // Evaluations
@@ -104,6 +105,7 @@ export class PromptLayerClient {
104
105
  getToolRegistry(identifier: string, params?: Body) { return this.get(`/api/public/v2/tool-registry/${this.enc(identifier)}`, params); }
105
106
  createToolRegistry(body: Body) { return this.post("/api/public/v2/tool-registry", body); }
106
107
  createToolVersion(identifier: string, body: Body) { return this.post(`/api/public/v2/tool-registry/${this.enc(identifier)}/versions`, body); }
108
+ testExecuteToolRegistry(identifier: string, body: Body, query?: Body) { return this.post(`/api/public/v2/tool-registry/${this.enc(identifier)}/test-execute${buildQueryParams(query)}`, body); }
107
109
 
108
110
  // Folders
109
111
  createFolder(body: Body) { return this.post("/api/public/v2/folders", body); }
@@ -112,4 +114,17 @@ export class PromptLayerClient {
112
114
  moveFolderEntities(body: Body) { return this.post("/api/public/v2/folders/entities", body); }
113
115
  deleteFolderEntities(body: Body) { return this.request("/api/public/v2/folders/entities", { method: "DELETE", body: JSON.stringify(body) }); }
114
116
  resolveFolderId(params: Body) { return this.get("/api/public/v2/folders/resolve-id", params); }
117
+
118
+ // Skill Collections
119
+ listSkillCollections() { return this.get("/api/public/v2/skill-collections"); }
120
+ createSkillCollection(body: Body) { return this.post("/api/public/v2/skill-collections", body); }
121
+ getSkillCollection(identifier: string, params?: Body) { return this.get(`/api/public/v2/skill-collections/${this.enc(identifier)}`, params); }
122
+ updateSkillCollection(identifier: string, body: Body) { return this.patch(`/api/public/v2/skill-collections/${this.enc(identifier)}`, body); }
123
+ saveSkillCollectionVersion(identifier: string, body: Body) { return this.post(`/api/public/v2/skill-collections/${this.enc(identifier)}/versions`, body); }
124
+
125
+ // Analytics
126
+ getRequestAnalytics(body: Body) { return this.post("/api/public/v2/requests/analytics", body); }
127
+
128
+ // Prompt template patch
129
+ patchPromptTemplateVersion(identifier: string, body: Body) { return this.patch(`/rest/prompt-templates/${this.enc(identifier)}`, body); }
115
130
  }
package/src/handlers.ts CHANGED
@@ -80,6 +80,8 @@ export function registerAllTools(server: any) {
80
80
  (r) => { const { rows, total, page, pages } = r as { rows?: unknown[]; total?: number; page?: number; pages?: number }; return `${rows?.length ?? 0} row(s) (page ${page ?? 1}/${pages ?? 1}, total ${total ?? "?"})`; });
81
81
  reg(t["create-draft-dataset-version"], (c, a) => c.createDraftDatasetVersion(body(a)), () => "Draft dataset version created");
82
82
  reg(t["add-request-log-to-dataset"], (c, a) => c.addRequestLogToDatasetVersion(body(a)), () => "Request log added to draft dataset");
83
+ reg(t["add-trace-to-dataset"], (c, a) => c.addTraceToDatasetVersion(body(a)),
84
+ (r) => { const m = (r as { mode?: string }).mode; return m ? `Trace added to draft dataset (mode: ${m})` : "Trace added to draft dataset"; });
83
85
  reg(t["save-draft-dataset-version"], (c, a) => c.saveDraftDatasetVersion(body(a)), () => "Draft dataset save initiated");
84
86
 
85
87
  // Evaluations
@@ -150,6 +152,20 @@ export function registerAllTools(server: any) {
150
152
  reg(t["create-tool-version"],
151
153
  (c, a) => { const { api_key: _, identifier, ...b } = a as { identifier: string; api_key?: string } & Args; return c.createToolVersion(identifier, b); },
152
154
  (r) => { const v = (r as { version?: { number?: number } }).version; return v ? `Version ${v.number} created` : "Version created"; });
155
+ reg(t["test-execute-tool-registry"],
156
+ (c, a) => {
157
+ const { api_key: _, identifier, label, version, ...rest } = a as { identifier: string; api_key?: string; label?: string; version?: number } & Args;
158
+ const query: Record<string, unknown> = {};
159
+ if (label !== undefined) query.label = label;
160
+ if (version !== undefined) query.version = version;
161
+ return c.testExecuteToolRegistry(identifier, rest, query);
162
+ },
163
+ (r) => {
164
+ const res = (r as { result?: { status?: string; duration_ms?: number; error?: { message?: string } } }).result;
165
+ if (!res) return "Tool executed";
166
+ if (res.status === "error") return `Tool failed: ${res.error?.message ?? "unknown error"}`;
167
+ return `Tool executed (${res.duration_ms ?? 0} ms)`;
168
+ });
153
169
 
154
170
  // Folders
155
171
  reg(t["create-folder"], (c, a) => c.createFolder(body(a)), () => "Folder created");
@@ -164,4 +180,28 @@ export function registerAllTools(server: any) {
164
180
  (r) => { const c_ = (r as { moved_count?: number }).moved_count; return `Deleted ${c_ ?? 0} entity/entities`; });
165
181
  reg(t["resolve-folder-id"], (c, a) => c.resolveFolderId(body(a)),
166
182
  (r) => { const id = (r as { id?: number }).id; return id ? `Folder ID: ${id}` : "Folder not found"; });
183
+
184
+ // Skill Collections
185
+ reg(t["list-skill-collections"], (c) => c.listSkillCollections(),
186
+ (r) => { const cs = (r as { skill_collections?: unknown[] }).skill_collections; return `${cs?.length ?? 0} skill collection(s)`; });
187
+ reg(t["create-skill-collection"], (c, a) => c.createSkillCollection(body(a)),
188
+ (r) => { const s = (r as { skill_collection?: { name?: string; id?: string } }).skill_collection; return s ? `Skill collection "${s.name}" created (ID: ${s.id})` : "Skill collection created"; });
189
+ reg(t["get-skill-collection"],
190
+ (c, a) => { const { api_key: _, identifier, ...p } = a as { identifier: string; api_key?: string } & Args; return c.getSkillCollection(identifier, p); },
191
+ (r) => { const s = (r as { skill_collection?: { name?: string }; version?: { version_number?: number } }); const name = s.skill_collection?.name ?? ""; const v = s.version?.version_number; return v !== undefined ? `Skill collection "${name}" v${v} retrieved` : `Skill collection "${name}" retrieved`; });
192
+ reg(t["update-skill-collection"],
193
+ (c, a) => { const { api_key: _, identifier, ...b } = a as { identifier: string; api_key?: string } & Args; return c.updateSkillCollection(identifier, b); },
194
+ () => "Skill collection updated");
195
+ reg(t["save-skill-collection-version"],
196
+ (c, a) => { const { api_key: _, identifier, ...b } = a as { identifier: string; api_key?: string } & Args; return c.saveSkillCollectionVersion(identifier, b); },
197
+ (r) => { const v = (r as { version?: { version_number?: number } }).version?.version_number; return v !== undefined ? `Version ${v} saved` : "Version saved"; });
198
+
199
+ // Analytics
200
+ reg(t["get-request-analytics"], (c, a) => c.getRequestAnalytics(body(a)),
201
+ (r) => { const x = r as { totalRequests?: number; totalCost?: number }; const reqs = x.totalRequests ?? 0; const cost = x.totalCost; return cost !== undefined ? `${reqs} request(s), $${cost} total cost` : `${reqs} request(s) analyzed`; });
202
+
203
+ // Prompt template patch
204
+ reg(t["patch-prompt-template-version"],
205
+ (c, a) => { const { api_key: _, identifier, ...b } = a as { identifier: string; api_key?: string } & Args; return c.patchPromptTemplateVersion(identifier, b); },
206
+ (r) => { const v = (r as { version_number?: number }).version_number; return v !== undefined ? `Patched — new version ${v} created` : "Patched — new version created"; });
167
207
  }
package/src/types.ts CHANGED
@@ -313,6 +313,15 @@ export const SaveDraftDatasetVersionArgsSchema = z.object({
313
313
  api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
314
314
  });
315
315
 
316
+ // ── Add Trace to Draft Dataset (POST /api/public/v2/dataset-versions/add-trace) ─────
317
+
318
+ export const AddTraceToDatasetVersionArgsSchema = z.object({
319
+ dataset_group_id: z.number().int().min(1).describe("ID of the dataset group containing the draft"),
320
+ trace_id: z.string().min(1).describe("ID of the trace to add as a dataset row"),
321
+ span_id: z.string().min(1).optional().describe("Optional span ID to anchor the row on a specific span subtree instead of the full trace"),
322
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
323
+ });
324
+
316
325
  // ── List Evaluations (GET /api/public/v2/evaluations) ────────────────────
317
326
 
318
327
  export const ListEvaluationsArgsSchema = z.object({
@@ -529,11 +538,19 @@ export const GetToolRegistryArgsSchema = z.object({
529
538
  api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
530
539
  });
531
540
 
541
+ export const ToolExecutionSchema = z.object({
542
+ type: z.literal("code"),
543
+ language: z.enum(["python", "javascript"]),
544
+ code: z.string().describe("Function body only. Signature is auto-generated; LLM args arrive as a single `args` object."),
545
+ });
546
+
532
547
  export const CreateToolRegistryArgsSchema = z.object({
533
548
  name: z.string().describe("Tool name (unique per workspace)"),
534
549
  tool_definition: z.record(z.unknown()).describe("Tool definition in OpenAI function-calling format: {type: 'function', function: {name, description, parameters}}"),
550
+ description: z.string().optional().describe("Optional human-readable description of the tool"),
535
551
  folder_id: z.number().int().optional().describe("Folder ID to place tool in"),
536
552
  commit_message: z.string().optional().describe("Commit message for the initial version"),
553
+ execution: ToolExecutionSchema.optional().describe("Optional sandbox-executable body. When set, PromptLayer auto-runs the body between LLM turns whenever a prompt uses this tool."),
537
554
  api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
538
555
  });
539
556
 
@@ -541,6 +558,17 @@ export const CreateToolVersionArgsSchema = z.object({
541
558
  identifier: z.string().describe("Tool ID (numeric) or name"),
542
559
  tool_definition: z.record(z.unknown()).describe("Updated tool definition in OpenAI function-calling format"),
543
560
  commit_message: z.string().optional().describe("Commit message describing what changed"),
561
+ execution: ToolExecutionSchema.optional().describe("Optional sandbox-executable body to attach to this version. See ToolExecutionSchema for details."),
562
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
563
+ });
564
+
565
+ export const TestExecuteToolRegistryArgsSchema = z.object({
566
+ identifier: z.string().describe("Tool ID (numeric) or name"),
567
+ inputs: z.record(z.unknown()).optional().describe("Arguments passed to the tool body, keyed by the tool's parameter names. Same shape the LLM would emit."),
568
+ execution: ToolExecutionSchema.optional().describe("In-flight override of the stored execution config. Lets you test unsaved code without creating a version."),
569
+ tool_definition: z.record(z.unknown()).optional().describe("In-flight override of the stored tool definition. Useful for testing a different function name without saving."),
570
+ label: z.string().optional().describe("Resolve version by label name (e.g. 'production'). Falls back to latest if neither label nor version given."),
571
+ version: z.number().int().optional().describe("Resolve by specific version number"),
544
572
  api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
545
573
  });
546
574
 
@@ -617,24 +645,129 @@ export const ResolveFolderIdArgsSchema = z.object({
617
645
  });
618
646
 
619
647
 
620
- // ── Search Request Logs (POST /api/public/v2/requests/search) ────────────
621
- // (StructuredFilter / StructuredFilterGroup are defined higher up so the
622
- // dataset-from-filter-params endpoint can reuse them.)
648
+ // ── Skill Collections ────────────────────────────────────────────────────
649
+ // Public API endpoints under /api/public/v2/skill-collections.
650
+ // MCP supports JSON bodies only (multipart/form-data with ZIP archive uploads
651
+ // is intentionally not exposed — agents should send file contents inline).
623
652
 
624
- export const SearchRequestLogsArgsSchema = z.object({
653
+ export const ListSkillCollectionsArgsSchema = z.object({
654
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
655
+ });
656
+
657
+ const SkillCollectionFileSchema = z.object({
658
+ path: z.string().describe("Relative file path inside the collection (e.g. 'README.md', 'src/util.ts')"),
659
+ content: z.string().optional().describe("File contents as a string. Defaults to empty string if omitted."),
660
+ });
661
+
662
+ export const CreateSkillCollectionArgsSchema = z.object({
663
+ name: z.string().describe("Collection name. Must be a valid root folder name (will be made unique within the workspace)."),
664
+ description: z.string().optional().describe("Optional human-readable description"),
665
+ folder_id: z.number().int().optional().describe("Folder ID to place the collection into"),
666
+ provider: z.string().optional().describe("Provider hint (e.g. 'claude', 'cursor'). Auto-detected from file paths if omitted."),
667
+ files: z.array(SkillCollectionFileSchema).optional().describe("Initial files for the collection. Each item is {path, content}."),
668
+ commit_message: z.string().optional().describe("Commit message for the initial version"),
669
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
670
+ });
671
+
672
+ export const GetSkillCollectionArgsSchema = z.object({
673
+ identifier: z.string().describe("Skill collection UUID, name, or root_path"),
674
+ label: z.string().optional().describe("Release label to pin the version (mutually exclusive with version)"),
675
+ version: z.number().int().min(1).optional().describe("Version number to pin (mutually exclusive with label)"),
676
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
677
+ });
678
+
679
+ export const UpdateSkillCollectionArgsSchema = z.object({
680
+ identifier: z.string().describe("Skill collection UUID, name, or root_path"),
681
+ name: z.string().optional().describe("New collection name (will be made unique within the workspace if it collides)"),
682
+ description: z.string().optional().describe("New description. Pass empty string to clear."),
683
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
684
+ });
685
+
686
+ const SkillCollectionFileMoveSchema = z.object({
687
+ old_path: z.string().describe("Existing relative path"),
688
+ new_path: z.string().describe("New relative path"),
689
+ });
690
+
691
+ export const SaveSkillCollectionVersionArgsSchema = z.object({
692
+ identifier: z.string().describe("Skill collection UUID, name, or root_path"),
693
+ file_updates: z.array(SkillCollectionFileSchema).optional().describe("Files to add or overwrite. Each item is {path, content}. Files not mentioned are carried forward from the previous version."),
694
+ moves: z.array(SkillCollectionFileMoveSchema).optional().describe("Files to rename: [{old_path, new_path}, ...]"),
695
+ deletes: z.array(z.string()).optional().describe("Relative paths of files to delete from the new version"),
696
+ commit_message: z.string().optional().describe("Commit message describing what changed"),
697
+ release_label: z.string().optional().describe("Release label to attach to the new version (e.g. 'production')"),
698
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
699
+ });
700
+
701
+
702
+ // ── Patch Prompt Template Version (PATCH /rest/prompt-templates/{identifier}) ──
703
+ // Partial update: fetches the base version, applies field-level patches, creates a new version.
704
+
705
+ export const PatchPromptTemplateVersionArgsSchema = z.object({
706
+ identifier: z.string().describe("Prompt template name or numeric ID"),
707
+ version: z.number().int().optional().describe("Base version number to patch from (mutually exclusive with label; defaults to latest)"),
708
+ label: z.string().optional().describe("Release label identifying the base version (mutually exclusive with version)"),
709
+ messages: z.union([z.record(z.unknown()), z.array(z.record(z.unknown()))]).optional().describe(
710
+ "Chat templates only. " +
711
+ "Object form: index-based patch ({\"0\": {...}}) — only listed indices are updated, others preserved. " +
712
+ "Array form: full replacement of all messages."
713
+ ),
714
+ tools: z.union([z.record(z.unknown()), z.array(z.record(z.unknown())), z.null()]).optional().describe(
715
+ "Chat templates only. Same patching behavior as messages. Pass null to remove all tools."
716
+ ),
717
+ functions: z.union([z.record(z.unknown()), z.array(z.record(z.unknown())), z.null()]).optional().describe(
718
+ "Chat templates only. Same patching behavior as messages. Pass null to remove all functions."
719
+ ),
720
+ function_call: z.union([z.string(), z.record(z.unknown()), z.null()]).optional().describe("Replaces the function_call setting. Null removes."),
721
+ tool_choice: z.union([z.string(), z.record(z.unknown()), z.null()]).optional().describe("Replaces the tool_choice setting. Null removes."),
722
+ content: z.union([z.record(z.unknown()), z.array(z.record(z.unknown()))]).optional().describe(
723
+ "Completion templates only. Same index-based / full-replacement behavior as messages."
724
+ ),
725
+ model_parameters: z.record(z.unknown()).optional().describe("Shallow-merged into existing model parameters (e.g. temperature, max_tokens)."),
726
+ response_format: z.union([z.record(z.unknown()), z.null()]).optional().describe("Convenience field to set response_format inside model parameters. Null removes. Cannot be combined with response_format inside model_parameters."),
727
+ commit_message: z.string().optional().describe("Commit message for the new version"),
728
+ release_labels: z.array(z.string()).optional().describe("Release labels to create or move to the new version"),
729
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
730
+ });
731
+
732
+
733
+
734
+
735
+ // ── Request log query (shared by /requests/search and /requests/analytics) ──
736
+ // Backend models: search uses PostStructuredSearchRequest = RequestLogQuery + page/per_page/include_prompt_name;
737
+ // analytics uses RequestLogQuery directly. We share the 4 RequestLogQuery fields here.
738
+
739
+ const RequestLogQueryShape = {
625
740
  filter_group: StructuredFilterGroupSchema.optional().describe("Filter group with AND/OR logic, supports nesting. Wrap multiple filters in an AND group."),
626
741
  q: z.string().optional().describe("Free-text search across prompt input and LLM output"),
627
- page: z.number().int().optional().describe("Page number (default: 1)"),
628
- per_page: z.number().int().optional().describe("Items per page (max: 25)"),
629
742
  sort_by: z.enum([
630
743
  "request_start_time", "input_tokens", "output_tokens", "cost", "latency_ms", "status",
631
744
  "turn_count", "tool_call_count",
632
745
  ]).optional().describe("Sort field"),
633
746
  sort_order: z.enum(["asc", "desc"]).optional().describe("Sort direction (must be provided with sort_by)"),
747
+ };
748
+
749
+ // ── Search Request Logs (POST /api/public/v2/requests/search) ────────────
750
+ // (StructuredFilter / StructuredFilterGroup are defined higher up so the
751
+ // dataset-from-filter-params endpoint can reuse them.)
752
+
753
+ export const SearchRequestLogsArgsSchema = z.object({
754
+ ...RequestLogQueryShape,
755
+ page: z.number().int().optional().describe("Page number (default: 1)"),
756
+ per_page: z.number().int().optional().describe("Items per page (max: 25)"),
634
757
  include_prompt_name: z.boolean().optional().describe("Include prompt template name in results"),
635
758
  api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
636
759
  });
637
760
 
761
+ // ── Get Request Analytics (POST /api/public/v2/requests/analytics) ───────
762
+ // Same RequestLogQuery body as search-request-logs but returns aggregated
763
+ // charts (requests/tokens/cost over time, latency stats, model & prompt
764
+ // breakdowns) instead of paginated rows.
765
+
766
+ export const GetRequestAnalyticsArgsSchema = z.object({
767
+ ...RequestLogQueryShape,
768
+ api_key: z.string().optional().describe("PromptLayer API key (optional, defaults to PROMPTLAYER_API_KEY env var)"),
769
+ });
770
+
638
771
  // ── Get Request (GET /api/public/v2/requests/{request_id}) ───────────────
639
772
 
640
773
  export const GetRequestArgsSchema = z.object({
@@ -880,6 +1013,12 @@ export const TOOL_DEFINITIONS = {
880
1013
  inputSchema: SaveDraftDatasetVersionArgsSchema,
881
1014
  annotations: { readOnlyHint: false },
882
1015
  },
1016
+ "add-trace-to-dataset": {
1017
+ name: "add-trace-to-dataset",
1018
+ description: "Add a trace as a row to the draft dataset version. Pass span_id to anchor on a specific span subtree instead of the full trace root. Requires create-draft first.",
1019
+ inputSchema: AddTraceToDatasetVersionArgsSchema,
1020
+ annotations: { readOnlyHint: false },
1021
+ },
883
1022
 
884
1023
  // ── Evaluations ─────────────────────────────────────────────────────
885
1024
  "list-evaluations": {
@@ -1020,16 +1159,22 @@ export const TOOL_DEFINITIONS = {
1020
1159
  },
1021
1160
  "create-tool-registry": {
1022
1161
  name: "create-tool-registry",
1023
- description: "Create a new tool in the Tool Registry with an initial version. The tool definition should be in OpenAI function-calling format.",
1162
+ description: "Create a new tool in the Tool Registry with an initial version. The tool definition should be in OpenAI function-calling format. Pass an optional `execution` payload to attach a sandbox-executable body that PromptLayer will auto-run between LLM turns.",
1024
1163
  inputSchema: CreateToolRegistryArgsSchema,
1025
1164
  annotations: { readOnlyHint: false },
1026
1165
  },
1027
1166
  "create-tool-version": {
1028
1167
  name: "create-tool-version",
1029
- description: "Create a new version of an existing tool in the Tool Registry. Each version is immutable this adds a new version with the updated definition.",
1168
+ description: "Create a new version of an existing tool in the Tool Registry. Each version is immutable - this adds a new version with the updated definition. Pass an optional `execution` payload to attach (or replace) the sandbox-executable body for this version.",
1030
1169
  inputSchema: CreateToolVersionArgsSchema,
1031
1170
  annotations: { readOnlyHint: false },
1032
1171
  },
1172
+ "test-execute-tool-registry": {
1173
+ name: "test-execute-tool-registry",
1174
+ description: "Run a tool's execution body in the sandbox against test inputs. Returns the body's return value plus stdout/stderr/duration. Useful for verifying a body before publishing. Pass `execution` and/or `tool_definition` to test unsaved overrides without creating a version. User-code errors return status='error' inside the result (HTTP 200); sandbox infrastructure failures return HTTP 502.",
1175
+ inputSchema: TestExecuteToolRegistryArgsSchema,
1176
+ annotations: { readOnlyHint: false },
1177
+ },
1033
1178
 
1034
1179
  // ── Folders ─────────────────────────────────────────────────────────
1035
1180
  "create-folder": {
@@ -1068,4 +1213,74 @@ export const TOOL_DEFINITIONS = {
1068
1213
  inputSchema: ResolveFolderIdArgsSchema,
1069
1214
  annotations: { readOnlyHint: true },
1070
1215
  },
1216
+
1217
+ // ── Skill Collections ───────────────────────────────────────────────
1218
+ "list-skill-collections": {
1219
+ name: "list-skill-collections",
1220
+ description: "List all skill collections in the workspace. Returns each collection's UUID, name, root_path, provider, description, and timestamps.",
1221
+ inputSchema: ListSkillCollectionsArgsSchema,
1222
+ annotations: { readOnlyHint: true },
1223
+ },
1224
+ "create-skill-collection": {
1225
+ name: "create-skill-collection",
1226
+ description:
1227
+ "Create a new skill collection with optional initial files. Each file is {path, content} where path is relative inside the collection " +
1228
+ "(e.g. 'README.md' or 'src/util.ts'). Provider is auto-detected from file paths if omitted (e.g. .claude/* → 'claude'). " +
1229
+ "Names are made unique within the workspace if they collide.",
1230
+ inputSchema: CreateSkillCollectionArgsSchema,
1231
+ annotations: { readOnlyHint: false },
1232
+ },
1233
+ "get-skill-collection": {
1234
+ name: "get-skill-collection",
1235
+ description:
1236
+ "Fetch a skill collection by UUID, name, or root_path. Returns the collection metadata, the version object, and a 'files' map of " +
1237
+ "{relative_path: file_content}. Pin a specific version with 'version' (number) or 'label' (release label) — these are mutually exclusive. " +
1238
+ "If neither is provided, returns the latest committed version.",
1239
+ inputSchema: GetSkillCollectionArgsSchema,
1240
+ annotations: { readOnlyHint: true },
1241
+ },
1242
+ "update-skill-collection": {
1243
+ name: "update-skill-collection",
1244
+ description: "Rename a skill collection or update its description. To save new file contents as a version, use save-skill-collection-version instead.",
1245
+ inputSchema: UpdateSkillCollectionArgsSchema,
1246
+ annotations: { readOnlyHint: false },
1247
+ },
1248
+ "save-skill-collection-version": {
1249
+ name: "save-skill-collection-version",
1250
+ description:
1251
+ "Save a new version of a skill collection. Apply file changes via three lists: " +
1252
+ "file_updates (add or overwrite — files not mentioned are carried forward unchanged), " +
1253
+ "moves (rename), and deletes (remove). Optionally attach a release_label to the new version.",
1254
+ inputSchema: SaveSkillCollectionVersionArgsSchema,
1255
+ annotations: { readOnlyHint: false },
1256
+ },
1257
+
1258
+ // ── Analytics ───────────────────────────────────────────────────────
1259
+ "get-request-analytics": {
1260
+ name: "get-request-analytics",
1261
+ description:
1262
+ "Aggregate analytics across request logs — totals (requests, tokens, cost), time-series breakdowns, latency percentiles, " +
1263
+ "and most-used models/prompts. Body is the same shape as search-request-logs (filter_group, q, sort_by, sort_order); the response is aggregated, not paginated rows. " +
1264
+ "Use this to answer questions like 'how much have we spent on GPT-4o this week?' or 'what's the p90 latency for prod traffic?'.",
1265
+ inputSchema: GetRequestAnalyticsArgsSchema,
1266
+ annotations: { readOnlyHint: true },
1267
+ },
1268
+
1269
+ // ── Prompt Template Patch ───────────────────────────────────────────
1270
+ "patch-prompt-template-version": {
1271
+ name: "patch-prompt-template-version",
1272
+ description:
1273
+ "Partially update a prompt template by creating a new version with merged changes. Fetches the base version (latest by default, or pin via version/label), " +
1274
+ "applies field-level patches, and creates a new version.\n\n" +
1275
+ "MERGE BEHAVIOR:\n" +
1276
+ " - messages/tools/functions/content: object form is index-based patch ({\"0\": {...}} updates only listed indices); array form fully replaces.\n" +
1277
+ " - tools/functions/function_call/tool_choice/response_format: pass null to remove.\n" +
1278
+ " - model_parameters: shallow merge — existing keys are preserved unless overwritten.\n" +
1279
+ " - release_labels: creates or moves the labels to the new version.\n\n" +
1280
+ "Use this for surgical edits (e.g. tweak the system message, add a tool, change temperature) without resending the whole template. " +
1281
+ "For a full rewrite, use publish-prompt-template instead.",
1282
+ inputSchema: PatchPromptTemplateVersionArgsSchema,
1283
+ annotations: { readOnlyHint: false },
1284
+ },
1285
+
1071
1286
  } as const;