mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-30 01:02:02 +00:00
refactor(core): reuse MCP prompt helpers (#45660)
This commit is contained in:
parent
d28b6e9ac2
commit
e4bc8b765b
3 changed files with 64 additions and 18 deletions
|
|
@ -10,17 +10,14 @@ import {
|
|||
CallToolResultSchema,
|
||||
ElicitationCompleteNotificationSchema,
|
||||
ElicitRequestSchema,
|
||||
GetPromptResultSchema,
|
||||
type Implementation,
|
||||
type ElicitRequestFormParams,
|
||||
type ElicitRequestParams,
|
||||
type ElicitRequestURLParams,
|
||||
type ElicitResult,
|
||||
ListPromptsResultSchema,
|
||||
ListRootsRequestSchema,
|
||||
ListToolsResultSchema,
|
||||
PromptListChangedNotificationSchema,
|
||||
PromptSchema,
|
||||
ResourceListChangedNotificationSchema,
|
||||
type LoggingMessageNotification,
|
||||
LoggingMessageNotificationSchema,
|
||||
|
|
@ -41,10 +38,6 @@ const toError = (error: unknown) => (error instanceof Error ? error : new Error(
|
|||
const TolerantListToolsResult = ListToolsResultSchema.extend({
|
||||
tools: ToolSchema.omit({ outputSchema: true }).array(),
|
||||
})
|
||||
const TolerantListPromptsResult = ListPromptsResultSchema.extend({
|
||||
prompts: PromptSchema.array(),
|
||||
})
|
||||
|
||||
export class NeedsAuthError extends Schema.TaggedError<NeedsAuthError>()("MCP.NeedsAuthError", {
|
||||
server: Schema.String,
|
||||
}) {
|
||||
|
|
@ -301,12 +294,8 @@ export const connect = Effect.fnUntraced(function* (
|
|||
const prompts = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
paginate(
|
||||
async (cursor) => {
|
||||
const params = cursor === undefined ? undefined : { cursor }
|
||||
return client.request({ method: "prompts/list", params }, TolerantListPromptsResult, {
|
||||
timeout: catalogTimeout,
|
||||
})
|
||||
},
|
||||
(cursor) =>
|
||||
client.listPrompts(cursor === undefined ? undefined : { cursor }, { timeout: catalogTimeout }),
|
||||
(result) => result.prompts,
|
||||
),
|
||||
catch: toError,
|
||||
|
|
@ -396,11 +385,7 @@ export const connect = Effect.fnUntraced(function* (
|
|||
prompt: (input) =>
|
||||
Effect.tryPromise({
|
||||
try: (signal) =>
|
||||
client.request(
|
||||
{ method: "prompts/get", params: { name: input.name, arguments: input.args ?? {} } },
|
||||
GetPromptResultSchema,
|
||||
{ signal, timeout: executionTimeout },
|
||||
),
|
||||
client.getPrompt({ name: input.name, arguments: input.args ?? {} }, { signal, timeout: executionTimeout }),
|
||||
catch: toError,
|
||||
}).pipe(
|
||||
Effect.map((result) => ({
|
||||
|
|
|
|||
30
packages/core/test/fixture/mcp-prompts.ts
Normal file
30
packages/core/test/fixture/mcp-prompts.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { Server } from "@modelcontextprotocol/sdk/server/index.js"
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
||||
import { GetPromptRequestSchema, ListPromptsRequestSchema } from "@modelcontextprotocol/sdk/types.js"
|
||||
|
||||
const server = new Server({ name: "prompts", version: "1.0.0" }, { capabilities: { prompts: {} } })
|
||||
|
||||
server.setRequestHandler(ListPromptsRequestSchema, ({ params }) =>
|
||||
Promise.resolve(
|
||||
params?.cursor === "page-2"
|
||||
? { prompts: [{ name: "second", description: "Second prompt" }] }
|
||||
: {
|
||||
prompts: [
|
||||
{
|
||||
name: "first",
|
||||
description: "First prompt",
|
||||
arguments: [{ name: "topic", description: "Topic to explain", required: true }],
|
||||
},
|
||||
],
|
||||
nextCursor: "page-2",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
server.setRequestHandler(GetPromptRequestSchema, ({ params }) =>
|
||||
Promise.resolve({
|
||||
messages: [{ role: "user", content: { type: "text", text: params.arguments?.topic ?? "missing" } }],
|
||||
}),
|
||||
)
|
||||
|
||||
await server.connect(new StdioServerTransport())
|
||||
|
|
@ -474,6 +474,37 @@ test("retains output schemas across paginated MCP discovery", async () => {
|
|||
])
|
||||
})
|
||||
|
||||
test("lists paginated prompts and invokes them through the MCP client", async () => {
|
||||
const result = await Effect.runPromise(
|
||||
Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const connection = yield* connect(
|
||||
"prompts",
|
||||
new ConfigMCP.Local({
|
||||
type: "local",
|
||||
command: [process.execPath, path.join(import.meta.dir, "fixture/mcp-prompts.ts")],
|
||||
}),
|
||||
import.meta.dir,
|
||||
)
|
||||
return {
|
||||
prompts: yield* connection.prompts(),
|
||||
result: yield* connection.prompt({ name: "first", args: { topic: "Effect" } }),
|
||||
}
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
expect(result.prompts).toEqual([
|
||||
{
|
||||
name: "first",
|
||||
description: "First prompt",
|
||||
arguments: [{ name: "topic", description: "Topic to explain", required: true }],
|
||||
},
|
||||
{ name: "second", description: "Second prompt", arguments: undefined },
|
||||
])
|
||||
expect(result.result).toEqual({ messages: [{ role: "user", content: { type: "text", text: "Effect" } }] })
|
||||
})
|
||||
|
||||
test("spawns local MCP servers through the location environment", async () => {
|
||||
const spawns: Array<ChildProcess.Command> = []
|
||||
const cwd = path.join(import.meta.dir, "fixture")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue