Just for information, patches need to be merged to support MCP OAuth 2.1 in the simple_oauth module.
1.
https://www.drupal.org/project/simple_oauth/issues/3547743
✨
Dynamic Client Registration Protocol (RFC7591)
Active
2.
https://www.drupal.org/project/simple_oauth/issues/3033472
✨
[PP-1] Support OpenID Connect Discovery
Needs review
3.
https://www.drupal.org/project/simple_oauth/issues/3182421
🐛
Implement nonce in OIDC
Needs work
Hey @michaellander, thanks for bringing this up. I agree, it's one of the must-have features and will be added to the top of the roadmap.
And after this comment it's your name unchecked again :/
This new "Contribution record" is harder than the previous one :/ I clicked your name and saved. Still nothing?
@ankitv18 I like "SiteInformation", but I don't have a clear idea of what to expose so that it doesn't become a security issue while still being a little bit more helpful. 😅
Ty @ankitv18, merged.
No, it's not. Thanks
Hey @askibinski, great to see someone interested in making it work.
As I remember, when I researched the auth implementation, there were the following requirements → Version 2025-06-18:
* OAuth 2.0 Authorization Server Metadata (RFC8414) → MUST
* OAuth 2.0 Dynamic Client Registration Protocol (RFC7591) → SHOULD
* OAuth 2.0 Protected Resource Metadata (RFC9728) → MUST
And Dynamic Client Registration is a MUST if we want to work with Claude Web or any other web-based clients. So I'd actually consider it a MUST.
I had a conversation with @bojan_dev, maintainer of the simple_oauth module, and:
For RFC8414, these need to be done:
https://www.drupal.org/project/simple_oauth/issues/3174705
✨
Implement JWKs (RFC 7517) and OAuth metadata (RFC 8414)
Needs work
https://www.drupal.org/project/simple_oauth/issues/3033472
✨
[PP-1] Support OpenID Connect Discovery
Needs review
RFC7591 and RFC9728 - nothing has been done yet.
As you pointed out, the previous version supported the PKCE Flow without these requirements. It’s interesting if the latest version also supports this as is (I got these requirements from the latest version, as I mentioned, and never checked the old one :D).
This can't be fixed for now. It's because of the JSON-RPC module, which we use to handle RPC requests.
Ah, you are right. Fix already pushed, thanks @jurgenhaas 🙌
Hey @jurgenhaas, I think this is due to the latest change that added granular access to the plugins.
By default, they’re only accessible to the authenticated role. Could you try editing the plugin configuration and checking "Anonymous user"? I think the plugin tools should appear again after that.
#3539318 also fixed this.
Hey @wjackson, thanks for the contribution!
Could you adjust it to work with the latest dev changes? The schema has changed a lot after the plugin configuration updates, so I think it will need some adjustments.
Pushed the change. Updated the logic for ID generation, no longer using MD5 for everything.
From now on, IDs are generated as: `[plugin name]_[tool name]`, and if the result exceeds the 64-character limit, it’s truncated and a 6-character MD5 hash suffix is added.
gagosha → changed the visibility of the branch 3531816-configurable-plugins to active.
gagosha → changed the visibility of the branch 3531816-configurable-plugins to hidden.
"AI Function Calling" is not the plugin, it's the plugin manager.
For the MCP module, its plugin: https://git.drupalcode.org/project/mcp/-/blob/1.x/modules/mcp_extra/src/...
The MCP module requires these plugins to wrap/proxy the actual plugins/plugin managers in its format and expose them. When exposing tools, the first part is the MCP plugin ID, and the second part is the tool name. For example, if there is no MD5, the tool name will be:
`aif_action_plugin__entity__unpublish_action__menu_link_content`
Hey @jibla @jurgenhaas,
For now, tool IDs are generated using two distinct parts: the plugin ID and the tool name. The plugin ID comes from the custom Drupal plugin. So for @Jurgenhaas photo, `aif` is the plugin ID, which stands for "AI Function Calling".
The second part is the MD5-hashed tool name, so there will be as many `aif_*` tools as the "AI Function Calling" plugin exposes.
We use MD5 for two reasons:
1. The Claude desktop application imposes a 64-character limit, and there might be other clients with similar restrictions.
2. Tools need to be discoverable. During the discovery phase, we use the first part (`aif`) to locate the plugin, and the second part, the MD5 hash, to locate the plugin's specific tool. Truncation wouldn’t work in this case, as it could lead to hash collisions (i.e. different tools ending up with the same name).
Hey @askibinski, this is related to: https://www.drupal.org/project/mcp/issues/3539318 ✨ Improve tools naming Active . You can also propose the general solutions in the parent issue.
@jibla @grasmash fixed and merged on dev
Hey, thanks for bringing this up. We will do that for the next release
Hey, @juc1
Just saw this catalog, it could be part of the roadmap, as it makes things easier, I guess. Will check
lekso surameli → credited gagosha → .
Hey @mpotter, thanks for the patch, but I don't think the module itself should handle CORS, as there's already a way to handle it within Drupal.
If it’s configured correctly, the module will also use those CORS settings, since it intercepts all of Drupal’s request/response flow.
Hey @askibinski, you’re not missing anything and you are right.
We need to change that part in the documentation. Thanks for mentioning it. The MD5 conversion is not part of the security in any case, and originally I wanted the tool names to stay original, but I couldn’t because of limitations with some clients.
@jibla, just update the above comment for DrushCaller. Since the allowlist categorization doesn’t seem so stable, I decided to make it a text area where the user can opt-in to allowed commands or use the * wildcard.
Summary
The MCP Content plugin's search-content
tool consistently fails with an "Unknown field: status" error when attempting to search for any content, even with empty filters. This affects all content searches through the MCP interface.
Steps to Reproduce
- Install MCP module (tested with latest dev version)
- Enable the Content plugin in MCP Extra
- Attempt to search for any content using the MCP content search tool:
{ "contentType": "YOUR_CONTENT_TYPE", "filters": [], "limit": 10 }
- Error occurs: "Unknown field: status"
Expected Behavior
Content search should work without errors and return matching nodes.
Actual Behavior
All content searches fail with "Unknown field: status" error, making the MCP content search functionality unusable.
Root Cause Analysis
The issue is in web/modules/contrib/mcp/modules/mcp_extra/src/Plugin/Mcp/Content.php
in the searchContent()
method around line 430:
$query = $this->entityTypeManager->getStorage('node')->getQuery() ->accessCheck(TRUE) ->condition('type', $contentType) ->condition('status', 1) // <-- This line adds a status condition ->range($offset, $limit) ->sort('created', 'DESC'); // <-- This line sorts by created field
The method automatically adds conditions for status
(to show only published content) and sorts by created
, but the isSupportedField()
method only recognizes title
, body
, and custom fields starting with field_
. Core Drupal fields like status
, created
, nid
, etc. are not included in the supported fields list.
Later in the code, when processing user filters, it validates all fields (including the automatically added ones) against isSupportedField()
, causing the error.
Proposed Solution
Modify the isSupportedField()
method to include core Drupal node fields that are used by the system:
private function isSupportedField( FieldDefinitionInterface $fieldDefinition, ): bool { $supportedTypes = [ 'string', 'string_long', 'list_string', 'datetime', 'boolean', 'text_long', ]; $fieldName = $fieldDefinition->getName(); // Core fields that are used by the system automatically if (in_array($fieldName, ['title', 'body', 'status', 'created', 'changed', 'nid', 'uid', 'type'])) { return TRUE; } if (str_starts_with($fieldName, 'field_') && in_array( $fieldDefinition->getType(), $supportedTypes ) ) { return TRUE; } return FALSE; }
Additional Notes
- This affects the latest dev version as of the time of this report
- The issue makes the entire MCP content search functionality unusable
- The fix is minimal and only adds recognition for core Drupal fields that the system already uses
- Core fields added:
status
,created
,changed
,nid
,uid
,type
Environment
- Drupal version: 10.4.3
- MCP module: Latest dev version
- PHP version: 8.3
Patch
The fix involves changing line ~560 in Content.php
from:
if (in_array($fieldName, ['title', 'body'])) {
to:
if (in_array($fieldName, ['title', 'body', 'status', 'created', 'changed', 'nid', 'uid', 'type'])) {
This ensures that core Drupal fields used by the search system are recognized as supported fields.
There are multiple ways the MCP config can be misconfigured. Some of them can’t be handled, as they don’t even hit the MCP route. Can you drop your MCP config so we can check, and add the error handling if something is missing and can be added?
It’s part of the module roadmap and a work in progress. Right now I’m in the research phase, so I’m open to conversation about how we can implement it.
This is a strange one, as the spec itself is model agnostic. Will check.
1. Add 'use mcp server' permission and access checks
- Added new permission
use mcp server
for basic MCP access - Updated routing to require this permission for the
/mcp/post
endpoint - Implemented
hasAccess()
checks in plugin base class with support for administrative override - Added permission validation in JSON-RPC methods (
ResourcesRead
,ToolsCall
)
2. Token authentication user selection
- Added user selection field in authentication settings form
- Token authentication can now be configured to use any user account
- Updated
McpAuthProvider
to load the configured user instead of hardcoded user 1 - Added validation to ensure configured user exists and is active
- Improved flood protection to use correct user ID
3. Content plugin opt-in behavior
- Changed default behavior to opt-in (all content types disabled by default)
- Updated form to clearly indicate opt-in behavior with description
- Modified
isContentTypeEnabled()
to returnFALSE
by default - Added test updates to reflect new behavior
4. DrushCaller security improvements
- Implemented command allowlist system with categorization by risk level:
- Safe commands (read-only, enabled by default)
- Moderate risk (cache operations, disabled by default)
- Dangerous commands (database/file modifications, disabled by default with warnings)
- Added form-based configuration for granular command control
- Implemented strict mode for exact command matching
- Added ability to configure custom commands
- Command validation in both
getTools()
andexecuteTool()
methods - Clear security warnings in UI for dangerous commands
Closing this for now, as I can’t reproduce the issue. If any reproducible criteria come up, I’ll reopen it.
Agreed — we're on the way to releasing a stable version, and documentation is part of that release.
Closed, already implemented
Closed, already implemented
Hey @cosmicdreams,
Yep, why not — we can definitely add Claude.md. Also, for the future, we might consider adding Cursor rules for the same purpose - to make plugin development even easier.
gagosha → changed the visibility of the branch 3501988-create-mcp-plugin to active.
gagosha → changed the visibility of the branch 3501988-create-mcp-plugin to hidden.
Hey @marcus_johansson,
I’ve pushed the initial version and placed the plugin in the right spot, under ai_agents_extra. This plugin exposes all accessible agents as tools and allows users to execute them.
gagosha → changed the visibility of the branch 3501988-create-mcp-plugin to active.
Hey @dan_metille,
Sorry for any inconvenience. We have our first release today, which should clarify the definition of 'soon'.
gagosha → changed the visibility of the branch 3501988-create-mcp-plugin to hidden.
Hey, what do you think about the following suggestion, @ejb503 @jibla?
As a baseline, we all agree with what @marcus_johansson posted in the Slack channel: “It should be hostable by a normal webserver/PHP stack, without any additional layers needed.” Based on this, we can proceed as follows:
Requirement:
To implement an MCP server that directly connects to MCP clients, we need the following (simplified):
- An SSE endpoint that allows clients to establish a connection and receive messages from the server. Method: GET.
- A regular HTTP POST endpoint that enables clients to send messages to the server. Method: POST.
With this setup, the POST endpoint would run the operation and queue the result, which the GET request could then check and return.
Proposal:
What if we add a configuration form with just one checkbox (defaulted to true) that determines whether the POST request should queue the operation result or return it directly?
This approach would allow us to maintain both implementations without any additional work. The core of MCP would return results compatible with the specification, creating a win-win situation. By default, no additional layer is needed, and everything would be standard, straightforward, and directly hostable by Drupal.