@prompt-ot/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -0
- package/dist/client.js +89 -0
- package/dist/client.js.map +1 -0
- package/dist/http.js +189 -0
- package/dist/http.js.map +1 -0
- package/dist/lib/env.js +34 -0
- package/dist/lib/env.js.map +1 -0
- package/dist/lib/errors.js +36 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/format.js +44 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/resources/prompts.js +129 -0
- package/dist/resources/prompts.js.map +1 -0
- package/dist/server.js +42 -0
- package/dist/server.js.map +1 -0
- package/dist/stdio.js +30 -0
- package/dist/stdio.js.map +1 -0
- package/dist/tools/blocks.js +156 -0
- package/dist/tools/blocks.js.map +1 -0
- package/dist/tools/prompts.js +201 -0
- package/dist/tools/prompts.js.map +1 -0
- package/dist/tools/test-cases.js +165 -0
- package/dist/tools/test-cases.js.map +1 -0
- package/dist/tools/variables.js +103 -0
- package/dist/tools/variables.js.map +1 -0
- package/dist/tools/versions.js +197 -0
- package/dist/tools/versions.js.map +1 -0
- package/package.json +61 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { registerPromptTools } from './tools/prompts.js';
|
|
3
|
+
import { registerBlockTools } from './tools/blocks.js';
|
|
4
|
+
import { registerVariableTools } from './tools/variables.js';
|
|
5
|
+
import { registerVersionTools } from './tools/versions.js';
|
|
6
|
+
import { registerTestCaseTools } from './tools/test-cases.js';
|
|
7
|
+
import { registerPromptResources } from './resources/prompts.js';
|
|
8
|
+
/**
|
|
9
|
+
* Build the MCP server with all tools and resources registered.
|
|
10
|
+
*
|
|
11
|
+
* Shared by both transport entry points (`stdio.ts` for local installs and
|
|
12
|
+
* `http.ts` for the hosted Streamable HTTP server). Both transports expose
|
|
13
|
+
* the same tool catalog so the LLM has identical capabilities regardless of
|
|
14
|
+
* how the user connects.
|
|
15
|
+
*
|
|
16
|
+
* Tool registration is delegated to per-area modules under `tools/` so each
|
|
17
|
+
* domain (prompts, blocks, variables, versions, test_cases) owns its own
|
|
18
|
+
* Zod schemas and handler logic.
|
|
19
|
+
*/
|
|
20
|
+
export function createMcpServer(opts) {
|
|
21
|
+
const server = new McpServer({
|
|
22
|
+
name: 'promptot',
|
|
23
|
+
version: '0.1.0',
|
|
24
|
+
});
|
|
25
|
+
// Tool modules — order doesn't matter functionally, but we register prompts
|
|
26
|
+
// first because the rest of the catalog operates on prompt subresources.
|
|
27
|
+
registerPromptTools(server, opts.client);
|
|
28
|
+
registerBlockTools(server, opts.client);
|
|
29
|
+
registerVariableTools(server, opts.client);
|
|
30
|
+
registerVersionTools(server, opts.client);
|
|
31
|
+
registerTestCaseTools(server, opts.client);
|
|
32
|
+
// Resources — URI-addressable read-only data exposed via the @ picker
|
|
33
|
+
// in clients like Claude Desktop.
|
|
34
|
+
registerPromptResources(server, opts.client);
|
|
35
|
+
// clientName is currently informational only — the PromptOTClient already
|
|
36
|
+
// forwards it as X-PromptOT-Client-Name on every request. Future tool
|
|
37
|
+
// modules might use it for client-specific behavior (e.g. different
|
|
38
|
+
// truncation defaults for ChatGPT vs Claude Desktop).
|
|
39
|
+
void opts.clientName;
|
|
40
|
+
return server;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAOjE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,IAA4B;IAC1D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,4EAA4E;IAC5E,yEAAyE;IACzE,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3C,oBAAoB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAE3C,sEAAsE;IACtE,kCAAkC;IAClC,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAE7C,0EAA0E;IAC1E,sEAAsE;IACtE,oEAAoE;IACpE,sDAAsD;IACtD,KAAK,IAAI,CAAC,UAAU,CAAC;IAErB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/stdio.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* stdio entry point for @prompt-ot/mcp.
|
|
4
|
+
*
|
|
5
|
+
* Spawned by MCP clients (Claude Desktop, Cursor, Codex CLI, Windsurf, Zed)
|
|
6
|
+
* via `npx -y @prompt-ot/mcp`. Reads PROMPTOT_API_KEY from env and speaks
|
|
7
|
+
* JSON-RPC over stdin/stdout.
|
|
8
|
+
*
|
|
9
|
+
* stdout is reserved for the MCP protocol — all logging goes to stderr.
|
|
10
|
+
*/
|
|
11
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
|
+
import { readEnv, requireApiKey } from './lib/env.js';
|
|
13
|
+
import { PromptOTClient } from './client.js';
|
|
14
|
+
import { createMcpServer } from './server.js';
|
|
15
|
+
async function main() {
|
|
16
|
+
const env = readEnv();
|
|
17
|
+
requireApiKey(env);
|
|
18
|
+
const client = new PromptOTClient(env);
|
|
19
|
+
const server = createMcpServer({ client, clientName: env.clientName });
|
|
20
|
+
const transport = new StdioServerTransport();
|
|
21
|
+
await server.connect(transport);
|
|
22
|
+
if (env.debug) {
|
|
23
|
+
process.stderr.write(`[promptot-mcp] Ready (client=${env.clientName}, api=${env.apiUrl})\n`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
main().catch((err) => {
|
|
27
|
+
process.stderr.write(`[promptot-mcp] Fatal error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=stdio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,aAAa,CAAC,GAAG,CAAC,CAAC;IAEnB,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IAEvE,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,CAAC,UAAU,SAAS,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC;IAC/F,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { isPromptOTError } from '../lib/errors.js';
|
|
3
|
+
import { jsonContent, textContent } from '../lib/format.js';
|
|
4
|
+
/**
|
|
5
|
+
* MCP tool registrations for the /api/v1/blocks endpoints.
|
|
6
|
+
*
|
|
7
|
+
* Each tool maps 1:1 to a public-api endpoint and uses inline Zod schemas
|
|
8
|
+
* (the MCP SDK 1.29 expects a ZodRawShapeCompat — a record of Zod schemas,
|
|
9
|
+
* not a wrapped ZodObject).
|
|
10
|
+
*
|
|
11
|
+
* All errors from PromptOTClient are caught and surfaced to the LLM as
|
|
12
|
+
* `isError: true` content blocks with human-readable hints from PromptOTError.
|
|
13
|
+
*/
|
|
14
|
+
export function registerBlockTools(server, client) {
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// list_blocks
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
server.registerTool('list_blocks', {
|
|
19
|
+
title: 'List blocks for a prompt',
|
|
20
|
+
description: 'List all blocks for a prompt in their current sort order. Returns each block\'s id, type, title, content, sort_order, enabled, locked, and is_required flags. Use create_block, update_block, or reorder_blocks to modify the prompt structure.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt whose blocks to list.'),
|
|
23
|
+
},
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
try {
|
|
26
|
+
const data = await client.get('/api/v1/blocks', {
|
|
27
|
+
tool: 'list_blocks',
|
|
28
|
+
query: { prompt_id: args.prompt_id },
|
|
29
|
+
});
|
|
30
|
+
return jsonContent({ count: data.length, blocks: data });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
if (isPromptOTError(err))
|
|
34
|
+
return { content: err.toMcpContent(), isError: true };
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// create_block
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
server.registerTool('create_block', {
|
|
42
|
+
title: 'Create a new block on a prompt',
|
|
43
|
+
description: 'Create a new block on an existing prompt. The block is appended to the end of the prompt by default; pass sort_order to insert at a specific position. Use the type field to pick one of the standard block types (role, context, instructions, guardrails, output_format) or "custom" for free-form sections. Returns the created block.',
|
|
44
|
+
inputSchema: {
|
|
45
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt to add the block to.'),
|
|
46
|
+
type: z
|
|
47
|
+
.enum(['role', 'context', 'instructions', 'guardrails', 'output_format', 'custom'])
|
|
48
|
+
.describe('Block type — determines styling and semantics in the editor.'),
|
|
49
|
+
title: z.string().min(1).max(200).describe('Display title for the block (shown as a heading when compiled).'),
|
|
50
|
+
content: z.string().optional().describe('Block content body in markdown. Defaults to empty.'),
|
|
51
|
+
sort_order: z.number().int().min(0).optional().describe('Position in the prompt (0-indexed). Defaults to appending at the end.'),
|
|
52
|
+
enabled: z.boolean().optional().describe('Whether the block is included in the compiled prompt. Defaults to true.'),
|
|
53
|
+
is_required: z.boolean().optional().describe('Mark the block as required so it cannot be deleted. Defaults to false.'),
|
|
54
|
+
},
|
|
55
|
+
}, async (args) => {
|
|
56
|
+
try {
|
|
57
|
+
const data = await client.post('/api/v1/blocks', args, { tool: 'create_block' });
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: `Created block "${data.title}" (id: ${data.id})\n\n${JSON.stringify(data, null, 2)}`,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
if (isPromptOTError(err))
|
|
69
|
+
return { content: err.toMcpContent(), isError: true };
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// update_block
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
server.registerTool('update_block', {
|
|
77
|
+
title: 'Update an existing block',
|
|
78
|
+
description: 'Update fields on an existing block. Only the provided fields are changed — omitted fields are left untouched. Locked blocks reject content edits. Returns the updated block.',
|
|
79
|
+
inputSchema: {
|
|
80
|
+
block_id: z.string().uuid().describe('The UUID of the block to update.'),
|
|
81
|
+
title: z.string().min(1).max(200).optional().describe('New display title for the block.'),
|
|
82
|
+
content: z.string().optional().describe('New markdown content for the block.'),
|
|
83
|
+
enabled: z.boolean().optional().describe('Enable or disable the block in the compiled output.'),
|
|
84
|
+
sort_order: z.number().int().min(0).optional().describe('New position of the block in the prompt (0-indexed).'),
|
|
85
|
+
},
|
|
86
|
+
}, async (args) => {
|
|
87
|
+
try {
|
|
88
|
+
const { block_id, ...rest } = args;
|
|
89
|
+
const patch = {};
|
|
90
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
91
|
+
if (value !== undefined)
|
|
92
|
+
patch[key] = value;
|
|
93
|
+
}
|
|
94
|
+
const data = await client.patch(`/api/v1/blocks/${block_id}`, patch, { tool: 'update_block' });
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: 'text',
|
|
99
|
+
text: `Updated block "${data.title}" (id: ${data.id})\n\n${JSON.stringify(data, null, 2)}`,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
if (isPromptOTError(err))
|
|
106
|
+
return { content: err.toMcpContent(), isError: true };
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// delete_block
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
server.registerTool('delete_block', {
|
|
114
|
+
title: 'Delete a block',
|
|
115
|
+
description: 'Permanently delete a block from a prompt. Required blocks (such as the default "role" and "instructions" blocks) cannot be deleted — the API will return an error in that case. Always confirm with the user before calling this tool.',
|
|
116
|
+
inputSchema: {
|
|
117
|
+
block_id: z.string().uuid().describe('The UUID of the block to delete.'),
|
|
118
|
+
},
|
|
119
|
+
}, async (args) => {
|
|
120
|
+
try {
|
|
121
|
+
await client.delete(`/api/v1/blocks/${args.block_id}`, {
|
|
122
|
+
tool: 'delete_block',
|
|
123
|
+
});
|
|
124
|
+
return textContent(`Block ${args.block_id} deleted.`);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
if (isPromptOTError(err))
|
|
128
|
+
return { content: err.toMcpContent(), isError: true };
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// reorder_blocks
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
server.registerTool('reorder_blocks', {
|
|
136
|
+
title: 'Reorder blocks within a prompt',
|
|
137
|
+
description: 'Reorder all blocks on a prompt by passing the block UUIDs in the desired order. Each block\'s sort_order is set to its index in the array. All block IDs must belong to the given prompt or the call is rejected.',
|
|
138
|
+
inputSchema: {
|
|
139
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt whose blocks to reorder.'),
|
|
140
|
+
block_ids: z
|
|
141
|
+
.array(z.string().uuid())
|
|
142
|
+
.describe('All block IDs in the desired order. Each block\'s sort_order will be set to its index.'),
|
|
143
|
+
},
|
|
144
|
+
}, async (args) => {
|
|
145
|
+
try {
|
|
146
|
+
await client.post('/api/v1/blocks/reorder', { prompt_id: args.prompt_id, block_ids: args.block_ids }, { tool: 'reorder_blocks' });
|
|
147
|
+
return textContent(`Reordered ${args.block_ids.length} block${args.block_ids.length === 1 ? '' : 's'} on prompt ${args.prompt_id}.`);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
if (isPromptOTError(err))
|
|
151
|
+
return { content: err.toMcpContent(), isError: true };
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../src/tools/blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { isPromptOTError } from '../lib/errors.js';
|
|
3
|
+
import { jsonContent, textContent, truncateText } from '../lib/format.js';
|
|
4
|
+
/**
|
|
5
|
+
* MCP tool registrations for the /api/v1/prompts endpoints.
|
|
6
|
+
*
|
|
7
|
+
* Each tool maps 1:1 to a public-api endpoint and uses Zod schemas defined
|
|
8
|
+
* inline (not imported from @prompt-ot/shared) for two reasons:
|
|
9
|
+
* 1. The MCP SDK 1.29 needs ZodRawShapeCompat — a record of Zod schemas,
|
|
10
|
+
* not a ZodObject — and exposing `.shape` from a complex shared schema
|
|
11
|
+
* can drift between versions.
|
|
12
|
+
* 2. Some MCP-specific options (truncate, max_tokens) don't exist on the
|
|
13
|
+
* API schemas and need to be added at the MCP layer.
|
|
14
|
+
*
|
|
15
|
+
* All errors from PromptOTClient are caught and surfaced to the LLM as
|
|
16
|
+
* `isError: true` content blocks with human-readable hints from PromptOTError.
|
|
17
|
+
*/
|
|
18
|
+
export function registerPromptTools(server, client) {
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// list_prompts
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
server.registerTool('list_prompts', {
|
|
23
|
+
title: 'List prompts',
|
|
24
|
+
description: 'List all prompts in the PromptOT project this MCP key is scoped to. Returns id, name, description, tags, and updated_at for each. Use get_prompt to fetch the full content of a specific one.',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
limit: z.number().int().min(1).max(200).optional().describe('Maximum prompts to return (default 50).'),
|
|
27
|
+
},
|
|
28
|
+
}, async (args) => {
|
|
29
|
+
try {
|
|
30
|
+
const data = await client.get('/api/v1/prompts', { tool: 'list_prompts' });
|
|
31
|
+
const limited = args.limit ? data.slice(0, args.limit) : data.slice(0, 50);
|
|
32
|
+
return jsonContent({ count: limited.length, total: data.length, prompts: limited });
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
if (isPromptOTError(err))
|
|
36
|
+
return { content: err.toMcpContent(), isError: true };
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// get_prompt
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
server.registerTool('get_prompt', {
|
|
44
|
+
title: 'Get a prompt with blocks',
|
|
45
|
+
description: 'Fetch a single prompt with its blocks, variables, and currently compiled output. Use this when the user wants to read or edit the structure of an existing prompt.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt to fetch.'),
|
|
48
|
+
truncate: z.boolean().optional().describe('Truncate the compiled prompt text (default true).'),
|
|
49
|
+
max_tokens: z.number().int().min(100).max(20000).optional().describe('Maximum tokens to return when truncating (default 2000).'),
|
|
50
|
+
},
|
|
51
|
+
}, async (args) => {
|
|
52
|
+
try {
|
|
53
|
+
const data = await client.get(`/api/v1/prompts/${args.prompt_id}/full`, { tool: 'get_prompt' });
|
|
54
|
+
const truncated = truncateText(data.compiled_prompt, {
|
|
55
|
+
truncate: args.truncate,
|
|
56
|
+
maxTokens: args.max_tokens,
|
|
57
|
+
fullTextHint: `Use the resource promptot://prompts/${args.prompt_id}/markdown for the full text.`,
|
|
58
|
+
});
|
|
59
|
+
return jsonContent({
|
|
60
|
+
id: data.id,
|
|
61
|
+
name: data.name,
|
|
62
|
+
description: data.description,
|
|
63
|
+
tags: data.tags,
|
|
64
|
+
model_config: data.model_config,
|
|
65
|
+
blocks: data.blocks.map((b) => ({
|
|
66
|
+
id: b.id,
|
|
67
|
+
type: b.type,
|
|
68
|
+
title: b.title,
|
|
69
|
+
content: b.content,
|
|
70
|
+
sort_order: b.sort_order,
|
|
71
|
+
enabled: b.enabled,
|
|
72
|
+
locked: b.locked,
|
|
73
|
+
})),
|
|
74
|
+
variables: data.variables,
|
|
75
|
+
compiled_prompt: truncated,
|
|
76
|
+
token_count: data.token_count,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (isPromptOTError(err))
|
|
81
|
+
return { content: err.toMcpContent(), isError: true };
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// get_compiled_prompt
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
server.registerTool('get_compiled_prompt', {
|
|
89
|
+
title: 'Compile a prompt to markdown',
|
|
90
|
+
description: 'Get the compiled markdown output of a prompt with all blocks joined and {{variables}} substituted. Optionally pass variable_overrides to test what the prompt looks like with specific values. Returns the compiled text and token count.',
|
|
91
|
+
inputSchema: {
|
|
92
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt to compile.'),
|
|
93
|
+
truncate: z.boolean().optional().describe('Truncate the output (default true).'),
|
|
94
|
+
max_tokens: z.number().int().min(100).max(20000).optional().describe('Max tokens when truncating (default 2000).'),
|
|
95
|
+
},
|
|
96
|
+
}, async (args) => {
|
|
97
|
+
try {
|
|
98
|
+
const data = await client.get(`/api/v1/prompts/${args.prompt_id}/compile`, { tool: 'get_compiled_prompt' });
|
|
99
|
+
const truncated = truncateText(data.compiled_prompt, {
|
|
100
|
+
truncate: args.truncate,
|
|
101
|
+
maxTokens: args.max_tokens,
|
|
102
|
+
fullTextHint: `Use the resource promptot://prompts/${args.prompt_id}/markdown for the full text.`,
|
|
103
|
+
});
|
|
104
|
+
return jsonContent({
|
|
105
|
+
compiled_prompt: truncated,
|
|
106
|
+
token_count: data.token_count,
|
|
107
|
+
block_token_counts: data.block_token_counts,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (isPromptOTError(err))
|
|
112
|
+
return { content: err.toMcpContent(), isError: true };
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// create_prompt
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
server.registerTool('create_prompt', {
|
|
120
|
+
title: 'Create a new prompt',
|
|
121
|
+
description: 'Create a new prompt in the PromptOT project. Automatically initializes with five default blocks: role, context, instructions, guardrails, output_format. Use update_block afterwards to fill in the content. Returns the created prompt with its blocks.',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
name: z.string().min(1).max(200).describe('Display name for the prompt.'),
|
|
124
|
+
description: z.string().max(1000).optional().describe('Short description of what the prompt does.'),
|
|
125
|
+
tags: z.array(z.string().max(50)).max(10).optional().describe('Tags for grouping/filtering prompts.'),
|
|
126
|
+
folder_id: z.string().uuid().optional().describe('Optional folder to put the prompt in.'),
|
|
127
|
+
},
|
|
128
|
+
}, async (args) => {
|
|
129
|
+
try {
|
|
130
|
+
const data = await client.post('/api/v1/prompts', args, { tool: 'create_prompt' });
|
|
131
|
+
return linesAndJson(`Created prompt "${data.name}" (id: ${data.id})`, data);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (isPromptOTError(err))
|
|
135
|
+
return { content: err.toMcpContent(), isError: true };
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// update_prompt
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
server.registerTool('update_prompt', {
|
|
143
|
+
title: 'Update prompt metadata',
|
|
144
|
+
description: 'Update a prompt\'s metadata fields (name, description, tags, folder_id). Does NOT modify blocks or variables — use update_block / upsert_variable for those. Returns the updated prompt.',
|
|
145
|
+
inputSchema: {
|
|
146
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt to update.'),
|
|
147
|
+
name: z.string().min(1).max(200).optional(),
|
|
148
|
+
description: z.string().max(1000).nullable().optional(),
|
|
149
|
+
tags: z.array(z.string().max(50)).max(10).optional(),
|
|
150
|
+
folder_id: z.string().uuid().nullable().optional(),
|
|
151
|
+
},
|
|
152
|
+
}, async (args) => {
|
|
153
|
+
try {
|
|
154
|
+
const { prompt_id, ...patch } = args;
|
|
155
|
+
const data = await client.patch(`/api/v1/prompts/${prompt_id}`, patch, { tool: 'update_prompt' });
|
|
156
|
+
return linesAndJson(`Updated prompt "${data.name}"`, data);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
if (isPromptOTError(err))
|
|
160
|
+
return { content: err.toMcpContent(), isError: true };
|
|
161
|
+
throw err;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// delete_prompt
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
server.registerTool('delete_prompt', {
|
|
168
|
+
title: 'Delete a prompt permanently',
|
|
169
|
+
description: 'Permanently delete a prompt and all its blocks, variables, versions, and test cases. This action is IRREVERSIBLE. Requires the `prompts:delete` scope. Always confirm with the user before calling this tool.',
|
|
170
|
+
inputSchema: {
|
|
171
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt to delete.'),
|
|
172
|
+
confirm: z.literal(true).describe('Must be exactly true to confirm the deletion.'),
|
|
173
|
+
},
|
|
174
|
+
}, async (args) => {
|
|
175
|
+
try {
|
|
176
|
+
await client.delete(`/api/v1/prompts/${args.prompt_id}`, {
|
|
177
|
+
tool: 'delete_prompt',
|
|
178
|
+
});
|
|
179
|
+
return textContent(`Prompt ${args.prompt_id} deleted permanently.`);
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
if (isPromptOTError(err))
|
|
183
|
+
return { content: err.toMcpContent(), isError: true };
|
|
184
|
+
throw err;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
// Local helpers
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
function linesAndJson(headline, data) {
|
|
192
|
+
return {
|
|
193
|
+
content: [
|
|
194
|
+
{
|
|
195
|
+
type: 'text',
|
|
196
|
+
text: `${headline}\n\n${JSON.stringify(data, null, 2)}`,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/tools/prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { isPromptOTError } from '../lib/errors.js';
|
|
3
|
+
import { jsonContent, textContent } from '../lib/format.js';
|
|
4
|
+
/**
|
|
5
|
+
* MCP tool registrations for the /api/v1/test-cases endpoints.
|
|
6
|
+
*
|
|
7
|
+
* Test cases are reusable inputs (with optional variable overrides and
|
|
8
|
+
* evaluation criteria) that pair with a prompt and feed into the evaluations
|
|
9
|
+
* runner. The shapes here mirror the v1 router in apps/api/src/routes/public-api/test-cases.ts.
|
|
10
|
+
*
|
|
11
|
+
* Zod schemas are defined inline (rather than imported from @prompt-ot/shared)
|
|
12
|
+
* because the MCP SDK 1.29 takes a `ZodRawShapeCompat` (a flat record of Zod
|
|
13
|
+
* schemas) and exposing `.shape` from a complex shared schema can drift across
|
|
14
|
+
* versions.
|
|
15
|
+
*/
|
|
16
|
+
export function registerTestCaseTools(server, client) {
|
|
17
|
+
// Reusable evaluation criteria schema. The four `type` values match the
|
|
18
|
+
// database constraint and the JWT-gated route in routes/test-cases.ts.
|
|
19
|
+
const evaluationCriteriaSchema = z
|
|
20
|
+
.array(z.object({
|
|
21
|
+
type: z
|
|
22
|
+
.enum(['contains', 'not_contains', 'regex_match', 'similarity_score'])
|
|
23
|
+
.describe('Criteria type. similarity_score requires a threshold between 0 and 1.'),
|
|
24
|
+
value: z.string().describe('The substring, regex, or reference text to evaluate against.'),
|
|
25
|
+
threshold: z
|
|
26
|
+
.number()
|
|
27
|
+
.min(0)
|
|
28
|
+
.max(1)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Threshold between 0 and 1, used for similarity_score criteria.'),
|
|
31
|
+
}))
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('Optional list of evaluation criteria the test case is scored against.');
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// list_test_cases
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
server.registerTool('list_test_cases', {
|
|
38
|
+
title: 'List test cases for a prompt',
|
|
39
|
+
description: 'List all test cases attached to a prompt, ordered newest first. Each entry includes id, name, input_text, variable_overrides, expected_output, and evaluation_criteria. Use these as fixtures for the evaluations runner.',
|
|
40
|
+
inputSchema: {
|
|
41
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt to list test cases for.'),
|
|
42
|
+
},
|
|
43
|
+
}, async (args) => {
|
|
44
|
+
try {
|
|
45
|
+
const data = await client.get('/api/v1/test-cases', {
|
|
46
|
+
tool: 'list_test_cases',
|
|
47
|
+
query: { prompt_id: args.prompt_id },
|
|
48
|
+
});
|
|
49
|
+
return jsonContent({ count: data.length, test_cases: data });
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (isPromptOTError(err))
|
|
53
|
+
return { content: err.toMcpContent(), isError: true };
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// create_test_case
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
server.registerTool('create_test_case', {
|
|
61
|
+
title: 'Create a test case',
|
|
62
|
+
description: 'Create a new test case for a prompt. Provide an input_text fixture and optional variable_overrides, expected_output, and evaluation_criteria. The evaluations runner will use these to score the prompt against the input.',
|
|
63
|
+
inputSchema: {
|
|
64
|
+
prompt_id: z.string().uuid().describe('The UUID of the prompt to attach the test case to.'),
|
|
65
|
+
name: z.string().min(1).max(200).describe('Display name for the test case.'),
|
|
66
|
+
input_text: z.string().describe('The input fixture passed to the compiled prompt at run time.'),
|
|
67
|
+
variable_overrides: z
|
|
68
|
+
.record(z.string())
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('Optional map of variable key -> value overrides for this test case.'),
|
|
71
|
+
expected_output: z
|
|
72
|
+
.string()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe('Optional reference output used for similarity_score / human review.'),
|
|
75
|
+
evaluation_criteria: evaluationCriteriaSchema,
|
|
76
|
+
},
|
|
77
|
+
}, async (args) => {
|
|
78
|
+
try {
|
|
79
|
+
const data = await client.post('/api/v1/test-cases', args, { tool: 'create_test_case' });
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: `Created test case "${data.name}" (id: ${data.id})\n\n${JSON.stringify(data, null, 2)}`,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
if (isPromptOTError(err))
|
|
91
|
+
return { content: err.toMcpContent(), isError: true };
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// update_test_case
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
server.registerTool('update_test_case', {
|
|
99
|
+
title: 'Update a test case',
|
|
100
|
+
description: 'Update one or more fields on an existing test case. Only the provided fields are changed; omitted fields are left untouched. The test_case_id cannot be moved between prompts.',
|
|
101
|
+
inputSchema: {
|
|
102
|
+
test_case_id: z.string().uuid().describe('The UUID of the test case to update.'),
|
|
103
|
+
name: z.string().min(1).max(200).optional().describe('New display name.'),
|
|
104
|
+
input_text: z.string().optional().describe('New input fixture.'),
|
|
105
|
+
variable_overrides: z
|
|
106
|
+
.record(z.string())
|
|
107
|
+
.optional()
|
|
108
|
+
.describe('New map of variable overrides (replaces the existing map).'),
|
|
109
|
+
expected_output: z
|
|
110
|
+
.string()
|
|
111
|
+
.nullable()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('New expected output reference text. Pass null to clear.'),
|
|
114
|
+
evaluation_criteria: evaluationCriteriaSchema,
|
|
115
|
+
},
|
|
116
|
+
}, async (args) => {
|
|
117
|
+
try {
|
|
118
|
+
const { test_case_id, ...rest } = args;
|
|
119
|
+
// Strip undefined fields so the PATCH only touches what was sent.
|
|
120
|
+
const patch = {};
|
|
121
|
+
for (const [key, value] of Object.entries(rest)) {
|
|
122
|
+
if (value !== undefined) {
|
|
123
|
+
patch[key] = value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const data = await client.patch(`/api/v1/test-cases/${test_case_id}`, patch, { tool: 'update_test_case' });
|
|
127
|
+
return {
|
|
128
|
+
content: [
|
|
129
|
+
{
|
|
130
|
+
type: 'text',
|
|
131
|
+
text: `Updated test case "${data.name}"\n\n${JSON.stringify(data, null, 2)}`,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
if (isPromptOTError(err))
|
|
138
|
+
return { content: err.toMcpContent(), isError: true };
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// delete_test_case
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
server.registerTool('delete_test_case', {
|
|
146
|
+
title: 'Delete a test case permanently',
|
|
147
|
+
description: 'Permanently delete a test case. This action is IRREVERSIBLE. Always confirm with the user before calling this tool.',
|
|
148
|
+
inputSchema: {
|
|
149
|
+
test_case_id: z.string().uuid().describe('The UUID of the test case to delete.'),
|
|
150
|
+
},
|
|
151
|
+
}, async (args) => {
|
|
152
|
+
try {
|
|
153
|
+
await client.delete(`/api/v1/test-cases/${args.test_case_id}`, {
|
|
154
|
+
tool: 'delete_test_case',
|
|
155
|
+
});
|
|
156
|
+
return textContent(`Test case ${args.test_case_id} deleted permanently.`);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
if (isPromptOTError(err))
|
|
160
|
+
return { content: err.toMcpContent(), isError: true };
|
|
161
|
+
throw err;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=test-cases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-cases.js","sourceRoot":"","sources":["../../src/tools/test-cases.ts"],"names":[],"mappings":"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"}
|