From cb45baadde400c1560ad825e15787ce1cce38515 Mon Sep 17 00:00:00 2001 From: Ian Turgeon Date: Tue, 17 Feb 2026 15:06:42 -0500 Subject: [PATCH] Show Elicitation detail. Show form and URL To my knowledge, announcing Elicitation support has changed over time. At first, the client announced it supports elicitation as a whole. When URL mode was added, the capability announcement format changed to include that detail. This change looks for those details and falls back gracefully to the first implementation. The details are displayed in the readme matrix by putting form and URL support into the same column since they are associated under that feature. --- README.md | 82 ++++++++++++------------ scripts/generate-table.js | 7 +- src/mcp_client_capabilities/mcp_types.py | 3 +- src/types.ts | 2 +- src/validate.ts | 16 ++++- 5 files changed, 64 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 3412d91..bc250a3 100644 --- a/README.md +++ b/README.md @@ -96,47 +96,47 @@ most clients don't use versions anyway. This might change in the future. ### Clients supported -| Display name | [Resources](#resources) | [Prompts](#prompts) | [Tools](#tools) | [Discovery](#discovery) | [Sampling](#sampling) | [Tasks](#tasks) | [Roots](#roots) | [Elicitation](#elicitation) | +| Display name | [Resources](#resources) | [Prompts](#prompts) | [Tools](#tools) | [Discovery](#discovery) | [Sampling](#sampling) | [Tasks](#tasks) | [Roots](#roots) | [Elicitation](#elicitation) (form, url) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| [Alpic Playground](https://alpic.ai/blog/launch-week-2-introducing-the-alpic-playground) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | -| [Amazon Q Developer CLI](https://github.com/aws/amazon-q-developer-cli) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [AmpCode](https://ampcode.com) | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | -| [Apify MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | -| [Arcade](https://arcade.dev) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | -| [ChatGPT](https://chatgpt.com) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Cherry Studio](https://www.cherry-ai.com) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Claude Code](https://claude.com/product/claude-code) | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | -| [Claude.ai](https://claude.ai) | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Cline](https://cline.bot/) | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | -| [Continue CLI Client](https://www.continue.dev/) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Crush](https://github.com/charmbracelet/crush) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | -| [Cursor](https://cursor.com) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | -| [Dust](https://dust.tt) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Factory CLI](https://github.com/factory-ai/factory-cli) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Gemini CLI](https://geminicli.com/) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [GitGuardian](https://www.gitguardian.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | -| [GitHub Copilot CLI](https://github.com/features/copilot/cli) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [GitHub Copilot for Xcode](https://github.com/github/CopilotForXcode) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | -| [Glama](https://glama.ai/chat) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | -| [Google Antigravity](https://antigravity.google) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | -| [Goose](https://block.github.io/goose) | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Jan AI](https://jan.ai) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [JetBrains AI Assistant](https://plugins.jetbrains.com/plugin/22282-jetbrains-ai-assistant) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | -| [JetBrains AI Assistant with GitHub Copilot](https://plugins.jetbrains.com/plugin/22282-jetbrains-ai-assistant) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | -| [Kilo Code](https://github.com/Kilo-Org/kilocode) | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | -| [LibreChat](https://www.librechat.ai) | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [LobeHub](https://lobehub.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Make MCP Client](https://www.make.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Mistral AI: Le Chat](https://chat.mistral.ai) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | -| [N8N MCP Client](https://n8n.io) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [OpenAI Codex](https://openai.com/codex) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | -| [Opencode](https://opencode.ai) | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | -| [Postman](https://postman.com/downloads) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | -| [Raycast](https://www.raycast.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | -| [Roo Code](https://roocode.com) | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | -| [Visual Studio Code](https://code.visualstudio.com) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| [Windsurf Editor](https://codeium.com/windsurf) | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | -| [Zed Editor](https://zed.dev) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | +| [Alpic Playground](https://alpic.ai/blog/launch-week-2-introducing-the-alpic-playground) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅, ❌ | +| [Amazon Q Developer CLI](https://github.com/aws/amazon-q-developer-cli) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [AmpCode](https://ampcode.com) | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌, ❌ | +| [Apify MCP Client](https://apify.com/jiri.spilka/tester-mcp-client) | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Arcade](https://arcade.dev) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅, ❌ | +| [ChatGPT](https://chatgpt.com) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Cherry Studio](https://www.cherry-ai.com) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Claude Code](https://claude.com/product/claude-code) | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌, ❌ | +| [Claude.ai](https://claude.ai) | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Cline](https://cline.bot/) | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Continue CLI Client](https://www.continue.dev/) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Crush](https://github.com/charmbracelet/crush) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌, ❌ | +| [Cursor](https://cursor.com) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅, ❌ | +| [Dust](https://dust.tt) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Factory CLI](https://github.com/factory-ai/factory-cli) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Gemini CLI](https://geminicli.com/) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [GitGuardian](https://www.gitguardian.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅, ❌ | +| [GitHub Copilot CLI](https://github.com/features/copilot/cli) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [GitHub Copilot for Xcode](https://github.com/github/CopilotForXcode) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌, ❌ | +| [Glama](https://glama.ai/chat) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅, ✅ | +| [Google Antigravity](https://antigravity.google) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌, ❌ | +| [Goose](https://block.github.io/goose) | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Jan AI](https://jan.ai) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [JetBrains AI Assistant](https://plugins.jetbrains.com/plugin/22282-jetbrains-ai-assistant) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅, ❌ | +| [JetBrains AI Assistant with GitHub Copilot](https://plugins.jetbrains.com/plugin/22282-jetbrains-ai-assistant) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅, ❌ | +| [Kilo Code](https://github.com/Kilo-Org/kilocode) | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌, ❌ | +| [LibreChat](https://www.librechat.ai) | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [LobeHub](https://lobehub.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Make MCP Client](https://www.make.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Mistral AI: Le Chat](https://chat.mistral.ai) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅, ❌ | +| [N8N MCP Client](https://n8n.io) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [OpenAI Codex](https://openai.com/codex) | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅, ❌ | +| [Opencode](https://opencode.ai) | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Postman](https://postman.com/downloads) | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅, ❌ | +| [Raycast](https://www.raycast.com) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌, ❌ | +| [Roo Code](https://roocode.com) | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Visual Studio Code](https://code.visualstudio.com) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅, ✅ | +| [Windsurf Editor](https://codeium.com/windsurf) | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌, ❌ | +| [Zed Editor](https://zed.dev) | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌, ❌ | ### Column explanations @@ -148,7 +148,7 @@ most clients don't use versions anyway. This might change in the future. - **Sampling**: Whether the client supports sampling from an LLM. This allows the server to request the client to generate text using its language model. - **Tasks**: Whether the client supports task-augmented tool calls. This enables asynchronous execution where the server can poll task status and retrieve results after completion, useful for expensive or long-running operations. - **Roots**: Whether the client supports managing root directories. Roots define the workspace or directories that the client wants the server to have access to. -- **Elicitation**: Whether the client supports elicitation from the server. This allows the server to request additional information or clarification from the client during interactions. +- **Elicitation**: Whether the client supports elicitation from the server. This allows the server to request additional information or clarification from the client during interactions. Clients may support **form**-based elicitation (structured input fields), **url**-based elicitation (opening a URL for the user), or both. ## Usage diff --git a/scripts/generate-table.js b/scripts/generate-table.js index c588e27..ad2e75e 100644 --- a/scripts/generate-table.js +++ b/scripts/generate-table.js @@ -7,7 +7,7 @@ const readmePath = path.join(__dirname, '../README.md'); const clients = JSON.parse(fs.readFileSync(jsonPath, 'utf8')); // Generate table content (header + rows) -const tableHeader = `| Display name | [Resources](#resources) | [Prompts](#prompts) | [Tools](#tools) | [Discovery](#discovery) | [Sampling](#sampling) | [Tasks](#tasks) | [Roots](#roots) | [Elicitation](#elicitation) | +const tableHeader = `| Display name | [Resources](#resources) | [Prompts](#prompts) | [Tools](#tools) | [Discovery](#discovery) | [Sampling](#sampling) | [Tasks](#tasks) | [Roots](#roots) | [Elicitation](#elicitation) (form, url) | | --- | --- | --- | --- | --- | --- | --- | --- | --- |`; // Track seen display names to skip duplicates @@ -31,7 +31,10 @@ const tableRows = Object.entries(clients) const sampling = clientData.sampling ? '✅' : '❌'; const tasks = clientData.tasks?.requests?.tools?.call ? '✅' : '❌'; const roots = clientData.roots ? '✅' : '❌'; - const elicitation = clientData.elicitation ? '✅' : '❌'; + const hasElicitation = !!clientData.elicitation; + const elicitationForm = hasElicitation && (!clientData.elicitation.url || clientData.elicitation.form) ? '✅' : '❌'; + const elicitationUrl = clientData.elicitation?.url ? '✅' : '❌'; + const elicitation = `${elicitationForm}, ${elicitationUrl}`; return `| ${displayName} | ${resources} | ${prompts} | ${tools} | ${discovery} | ${sampling} | ${tasks} | ${roots} | ${elicitation} |`; }) diff --git a/src/mcp_client_capabilities/mcp_types.py b/src/mcp_client_capabilities/mcp_types.py index b2f0228..eb1e1a1 100644 --- a/src/mcp_client_capabilities/mcp_types.py +++ b/src/mcp_client_capabilities/mcp_types.py @@ -35,7 +35,8 @@ class Experimental(TypedDict, total=False): class Elicitation(TypedDict, total=False): - pass + form: Optional[dict] + url: Optional[dict] class Sampling(TypedDict, total=False): diff --git a/src/types.ts b/src/types.ts index ead6a79..05c31b0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,7 +14,7 @@ export interface McpClientRecord { prompts?: { listChanged?: boolean }; tools?: { listChanged?: boolean }; tasks?: { requests?: { tools?: { call?: {} } } }; - elicitation?: {}; + elicitation?: { form?: {}; url?: {} }; sampling?: {}, roots?: { listChanged?: boolean }, completions?: {}; diff --git a/src/validate.ts b/src/validate.ts index 1480dfc..93fc5ae 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -159,10 +159,24 @@ function validateClientCapabilities(clientName: string, record: any): record is } } - // Validate elicitation capability (empty object) + // Validate elicitation capability if (record.elicitation !== undefined) { if (typeof record.elicitation !== 'object' || record.elicitation === null) { errors.push(`${clientName}.elicitation: must be an object`); + } else { + for (const key of Object.keys(record.elicitation)) { + if (key === 'form' || key === 'url') { + if (typeof record.elicitation[key] !== 'object' || record.elicitation[key] === null) { + errors.push(`${clientName}.elicitation.${key}: must be an object`); + } else { + for (const subKey of Object.keys(record.elicitation[key])) { + errors.push(`${clientName}.elicitation.${key}: unknown property '${subKey}'`); + } + } + } else { + errors.push(`${clientName}.elicitation: unknown property '${key}'`); + } + } } }