Skip to content

Commit fedc6db

Browse files
committed
feat(mcp): prompts
1 parent 36609cd commit fedc6db

File tree

4 files changed

+123
-13
lines changed

4 files changed

+123
-13
lines changed

js/packages/phoenix-mcp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"license": "Apache-2.0",
2424
"dependencies": {
2525
"@arizeai/phoenix-client": "workspace:*",
26-
"@modelcontextprotocol/sdk": "^1.8.0",
26+
"@modelcontextprotocol/sdk": "^1.9.0",
2727
"glob": "^11.0.1",
2828
"minimist": "^1.2.8",
2929
"zod": "^3.24.2"

js/packages/phoenix-mcp/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { initializeDatasetTools } from "./datasetTools.js";
88
import { initializeExperimentTools } from "./experimentTools.js";
99
import { initializePromptTools } from "./promptTools.js";
1010
import { initializeReadmeResources } from "./readmeResource.js";
11-
11+
import { initializePrompts } from "./prompts.js";
1212
const argv = minimist(process.argv.slice(2));
1313

1414
// Initialize Phoenix client
@@ -27,11 +27,11 @@ const server = new McpServer({
2727
name: "phoenix-mcp-server",
2828
version: "1.0.0",
2929
capabilities: {
30-
resources: {},
31-
tools: {},
30+
prompts: {},
3231
},
3332
});
3433

34+
initializePrompts({ client, server });
3535
initializePromptTools({ client, server });
3636
initializeExperimentTools({ client, server });
3737
initializeDatasetTools({ client, server });
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { PhoenixClient } from "@arizeai/phoenix-client";
2+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3+
import {
4+
GetPromptRequestSchema,
5+
ListPromptsRequestSchema,
6+
} from "@modelcontextprotocol/sdk/types.js";
7+
8+
const parseVariablesMustache = (template: string) => {
9+
const regex = /\{\{([^{}]+)\}\}/g;
10+
const variables = [];
11+
let match;
12+
while ((match = regex.exec(template))) {
13+
variables.push(match[1]);
14+
}
15+
return variables;
16+
};
17+
18+
const parseArgumentsFString = (template: string) => {
19+
const regex = /\{([^{}]+)\}/g;
20+
const variables = [];
21+
let match;
22+
while ((match = regex.exec(template))) {
23+
variables.push(match[1]);
24+
}
25+
return variables;
26+
};
27+
28+
export const initializePrompts = async ({
29+
client,
30+
server,
31+
}: {
32+
client: PhoenixClient;
33+
server: McpServer;
34+
}) => {
35+
server.server.setRequestHandler(ListPromptsRequestSchema, async () => {
36+
const promptsResponse = await client.GET("/v1/prompts");
37+
38+
if (!promptsResponse.data) {
39+
return {
40+
prompts: [],
41+
};
42+
}
43+
44+
// Get all the prompts and parse out the arguments
45+
const prompts = promptsResponse.data.data.map(async (prompt) => {
46+
const promptVersionResponse = await client.GET(
47+
"/v1/prompts/{prompt_identifier}/latest",
48+
{
49+
params: {
50+
path: {
51+
prompt_identifier: prompt.name,
52+
},
53+
},
54+
}
55+
);
56+
57+
const args: string[] = [];
58+
const template = promptVersionResponse.data?.data.template;
59+
const format = promptVersionResponse.data?.data.template_format;
60+
const parser =
61+
format === "F_STRING" ? parseArgumentsFString : parseVariablesMustache;
62+
if (template && template.type === "chat") {
63+
template.messages.forEach((message) => {
64+
const content = message.content;
65+
if (typeof content === "string") {
66+
args.push(...parser(content));
67+
}
68+
});
69+
}
70+
71+
return {
72+
name: prompt.name,
73+
description: prompt.description,
74+
arguments: args,
75+
};
76+
});
77+
78+
return { prompts: prompts };
79+
});
80+
81+
server.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
82+
// const args = request.params.arguments || {};
83+
// Get the latest version of the prompt
84+
const promptVersionResponse = await client.GET(
85+
"/v1/prompts/{prompt_identifier}/latest",
86+
{
87+
params: {
88+
path: {
89+
prompt_identifier: request.params.name,
90+
},
91+
},
92+
}
93+
);
94+
95+
const template = promptVersionResponse.data?.data.template;
96+
let messages: { role: string; content: string }[] = [];
97+
if (template && template.type === "chat") {
98+
messages = template.messages.map((message) => {
99+
return {
100+
role: message.role as string,
101+
content: message.content as string,
102+
};
103+
});
104+
}
105+
return {
106+
description: promptVersionResponse.data?.data.description,
107+
messages: messages,
108+
};
109+
});
110+
};

js/pnpm-lock.yaml

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)