From 3953dc40931e88fc1f85656a7f1b5fd1db57cd06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusufhan=20Sa=C3=A7ak?= Date: Fri, 10 Apr 2026 14:49:48 +0300 Subject: [PATCH] feat(everything): add URL elicitation example (SEP-1036) Add a trigger-url-elicitation-request tool to the Everything server that demonstrates SEP-1036 URL Elicitation. The tool sends an elicitation/create request with mode "url", asking the client to navigate the user to an external URL for out-of-band interaction (e.g., third-party OAuth authorization). The tool is conditionally registered only when the client declares elicitation.url capability, consistent with existing elicitation tools. Closes #3034 --- src/everything/tools/index.ts | 2 + .../tools/trigger-url-elicitation-request.ts | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/everything/tools/trigger-url-elicitation-request.ts diff --git a/src/everything/tools/index.ts b/src/everything/tools/index.ts index 1526f09dde..e8fa90dff7 100644 --- a/src/everything/tools/index.ts +++ b/src/everything/tools/index.ts @@ -16,6 +16,7 @@ import { registerTriggerLongRunningOperationTool } from "./trigger-long-running- import { registerTriggerSamplingRequestTool } from "./trigger-sampling-request.js"; import { registerTriggerSamplingRequestAsyncTool } from "./trigger-sampling-request-async.js"; import { registerTriggerElicitationRequestAsyncTool } from "./trigger-elicitation-request-async.js"; +import { registerTriggerUrlElicitationRequestTool } from "./trigger-url-elicitation-request.js"; import { registerSimulateResearchQueryTool } from "./simulate-research-query.js"; /** @@ -50,4 +51,5 @@ export const registerConditionalTools = (server: McpServer) => { // Bidirectional task tools - server sends requests that client executes as tasks registerTriggerSamplingRequestAsyncTool(server); registerTriggerElicitationRequestAsyncTool(server); + registerTriggerUrlElicitationRequestTool(server); }; diff --git a/src/everything/tools/trigger-url-elicitation-request.ts b/src/everything/tools/trigger-url-elicitation-request.ts new file mode 100644 index 0000000000..aa496adf45 --- /dev/null +++ b/src/everything/tools/trigger-url-elicitation-request.ts @@ -0,0 +1,92 @@ +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { + ElicitResultSchema, + CallToolResult, +} from "@modelcontextprotocol/sdk/types.js"; + +// Tool configuration +const name = "trigger-url-elicitation-request"; +const config = { + title: "Trigger URL Elicitation Request Tool", + description: + "Trigger a URL elicitation request (SEP-1036) that asks the client to " + + "navigate the user to an external URL for out-of-band interaction, such " + + "as OAuth authorization or payment flows.", + inputSchema: {}, +}; + +/** + * Registers the 'trigger-url-elicitation-request' tool. + * + * This tool demonstrates SEP-1036 URL Elicitation, where the server requests + * the client to open an external URL for the user. This is used for flows + * where sensitive data (credentials, payment info) must not transit through + * the MCP client, such as third-party OAuth authorization. + * + * The client responds with accept (user consented to navigate), decline, + * or cancel. The actual interaction happens out-of-band in the browser. + * + * Requires the client to declare `elicitation.url` capability. + * + * @param {McpServer} server - The McpServer instance where the tool will be registered. + */ +export const registerTriggerUrlElicitationRequestTool = ( + server: McpServer +) => { + const clientCapabilities = server.server.getClientCapabilities() || {}; + const elicitationCapability = clientCapabilities.elicitation as + | { url?: object } + | undefined; + const clientSupportsUrlElicitation = elicitationCapability?.url !== undefined; + + if (clientSupportsUrlElicitation) { + server.registerTool( + name, + config, + async (args, extra): Promise => { + const elicitationId = crypto.randomUUID(); + const elicitationResult = await extra.sendRequest( + { + method: "elicitation/create", + params: { + mode: "url", + elicitationId, + message: + "Please authorize access to your GitHub repositories. " + + "You will be redirected to GitHub to complete the authorization.", + url: "https://github.com/login/oauth/authorize?client_id=EXAMPLE_CLIENT_ID&scope=repo&state=example-state", + }, + }, + ElicitResultSchema, + { timeout: 10 * 60 * 1000 /* 10 minutes */ } + ); + + const content: CallToolResult["content"] = []; + + if (elicitationResult.action === "accept") { + content.push({ + type: "text", + text: "✅ User accepted the URL elicitation request and was directed to the external URL.", + }); + } else if (elicitationResult.action === "decline") { + content.push({ + type: "text", + text: "❌ User declined to navigate to the external URL.", + }); + } else if (elicitationResult.action === "cancel") { + content.push({ + type: "text", + text: "⚠️ User cancelled the URL elicitation dialog.", + }); + } + + content.push({ + type: "text", + text: `\nRaw result: ${JSON.stringify(elicitationResult, null, 2)}`, + }); + + return { content }; + } + ); + } +};