Skip to content

Exempt embedded Mattermost MCP tools from the MCP license gate - #924

Merged
crspeller merged 7 commits into
masterfrom
cursor/embedded-mcp-license-gate-2922
Jul 28, 2026
Merged

Exempt embedded Mattermost MCP tools from the MCP license gate#924
crspeller merged 7 commits into
masterfrom
cursor/embedded-mcp-license-gate-2922

Conversation

@crspeller

@crspeller crspeller commented Jul 24, 2026

Copy link
Copy Markdown
Member

Summary

On a Professional (or unlicensed) server, submitting tool decisions for embedded Mattermost MCP tools (e.g. read_channel, search_posts, create_post) failed with "Failed to submit tool decisions" in the approval UI and {"level":"error","msg":"feature not licensed","plugin_id":"mattermost-ai"} in the server log.

This PR fixes the issue by allowing the embedded MCP server on all plans.

Ticket Link

None

Screenshots

Captured from the live System Console of real Mattermost v11.9.1 servers running the actual builds of this branch (post-merge with master) and of current master. "Unlicensed" shots are from Team Edition (no license); the "licensed" shot is from Enterprise Edition with its auto-applied Entry license.

Before (unlicensed) After (unlicensed)
Before: remote MCP server configuration fully visible on an unlicensed server After: remote MCP server configuration hidden on an unlicensed server, licensed-feature chip shown

With a qualifying license (Entry, auto-applied on Enterprise Edition) the panel is unchanged:

After: licensed server shows the full remote MCP server configuration as before

Release Note

Fixed embedded Mattermost MCP tools (e.g. read_channel, search_posts, create_post) failing with "feature not licensed" on servers without an Entry, Enterprise, or Enterprise Advanced license. Embedded MCP tools and built-in tools now work without a license as basic tool integrations. Remote and external MCP servers still require a license: without one their tools are no longer supplied to agents at all, and the remote MCP server configuration UI is hidden in the System Console.

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Added enterprise licence-aware gating for remote/external MCP tools across tool discovery, loading, and agent execution.
    • System console now hides remote MCP server configuration when unlicensed (embedded Mattermost MCP remains available), with matching user-facing copy.
  • Bug Fixes

    • Tool-call and tool-result flows now enforce remote MCP licensing only (no blanket check), returning HTTP 403 when remote MCP isn’t licensed.
    • Remote MCP auth/prompt errors are suppressed when unlicensed.
  • Documentation

    • Updated admin and upgrade guides to clarify remote/external MCP licensing requirements.
  • Tests

    • Added coverage for remote MCP licence gating and HTTP status/error mapping.

cursoragent and others added 2 commits July 23, 2026 15:15
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…onsole

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
@cursor

cursor Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5de1bfccc6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +70 to +71
func (c *Conversations) isRemoteMCPLicensed() bool {
return c.licenseChecker != nil && c.licenseChecker.IsBasicsLicensed()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate remote auto-execution on the license

When an unlicensed server already has a remote MCP tool configured with an auto_run_in_dm or auto_run_everywhere policy, this predicate is never consulted: the initial DM path passes shouldAutoExecuteTool to the runner at conversations/conversations.go:215-216, and toolrunner/toolrunner.go:285-315 executes an all-approved batch directly without calling either approval handler. Consequently, remote tools can still run on an unlicensed server despite the new UI notice and approval checks; incorporate the license into tool availability or the auto-execution callback before the runner resolves the tool.

Useful? React with 👍 / 👎.

Comment thread conversations/tool_approval.go Outdated
Comment on lines +138 to +139
if (slices.Contains(acceptedToolIDs, b.ID) || b.WouldAutoExecute) && !c.isRemoteMCPLicensed() {
return ErrRemoteMCPNotLicensed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recheck auto-run policy before rejecting the click

When a mixed batch persisted a remote call with WouldAutoExecute=true and its policy is changed to ask or disabled before the user resolves the batch, this preflight returns 403 solely from the stale marker even if the remote ID is omitted from acceptedToolIDs. The execution branch at conversations/tool_approval.go:230 deliberately performs a fresh autoExec policy check and would reject rather than run that call, so the early return instead prevents the user from rejecting it or processing other calls in the batch; base this license decision on the fresh execution decision rather than WouldAutoExecute alone.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Remote MCP licensing is enforced when building tool contexts, approving tools, sharing results, serving API decisions, and configuring remote servers. Embedded MCP and built-in tools remain available without the remote MCP license, with updated tests and documentation.

Changes

Remote MCP licensing

Layer / File(s) Summary
Remote MCP context filtering
mcp/vetted_tools.go, llmcontext/..., conversations/*test.go
Remote MCP tools and authentication errors are excluded from unlicensed LLM contexts, while embedded and built-in tools remain available.
Conversation approval and sharing gates
conversations/tool_approval.go, conversations/*test.go
Remote MCP execution and result sharing require licensing; rejected or private decisions remain permitted, and failed checks avoid state mutation.
Tool decision API boundary
api/api_post.go, api/*test.go
Tool decision endpoints no longer apply blanket license checks, and remote MCP licensing errors return HTTP 403.
Remote MCP configuration UI
webapp/src/components/system_console/*, webapp/src/i18n/en.json
Unlicensed installations hide remote MCP configuration controls and show a qualifying-plan notice.
License requirement documentation
docs/admin_guide.md, docs/upgrading_to_2.0.md
Documentation distinguishes licensed remote or external MCP servers from unlicensed embedded MCP tools.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Admin
  participant MCPServers
  participant LicenseHook
  participant Conversations
  participant LLMContextBuilder
  Admin->>MCPServers: Open MCP configuration
  MCPServers->>LicenseHook: Read Basics license state
  LicenseHook-->>MCPServers: Licensed or unlicensed
  MCPServers-->>Admin: Show controls or qualifying-plan notice
  Conversations->>LicenseHook: Check remote MCP decision
  LicenseHook-->>Conversations: Allow or ErrRemoteMCPNotLicensed
  LLMContextBuilder->>LicenseHook: Check remote MCP availability
  LicenseHook-->>LLMContextBuilder: Include or filter remote tools
Loading

Suggested labels: Setup Cloud Test Server

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: embedded Mattermost MCP tools are exempted from the MCP license gate.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/embedded-mcp-license-gate-2922

Comment @coderabbitai help to get the list of available commands.

cursoragent and others added 2 commits July 24, 2026 13:54
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…cceptance

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

🤖 LLM Evaluation Results

OpenAI

⚠️ Overall: 21/28 tests passed (75.0%)

Provider Total Passed Failed Pass Rate
⚠️ OPENAI 28 21 7 75.0%

❌ Failed Evaluations

Show 7 failures

OPENAI

1. TestReactEval/[openai]_react_cat_message

  • Score: 0.00
  • Rubric: The word/emoji is a cat emoji or a heart/love emoji
  • Reason: The output is the text string "heart_eyes_cat", not an actual cat emoji (e.g., 😺) or heart/love emoji (e.g., ❤️). Therefore it does not meet the rubric requirement.

2. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: is a list of bugs
  • Reason: The output does not provide an actual list of bugs; it states inability to access bug reports and provides a blank template/table to be filled in. Therefore it is not a list of bugs.

3. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: includes a description of each bug
  • Reason: The output explicitly states it cannot see which bugs were reported and does not provide descriptions of any specific bugs; it only provides a blank template and instructions to paste bug reports.

4. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes each bug to a user
  • Reason: The output does not attribute any bugs to a user; it states it cannot access bug reports and provides an empty template with a 'Reported by' column but no actual user attributions.

5. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes the bug about trying to save without a color and the save button not doing anything to @maria.nunez
  • Reason: The output does not mention the specific bug about trying to save without a color or that the save button does nothing, nor does it attribute anything to @maria.nunez. It only asks the user to paste bug reports and provides a template.

6. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: the bug about the end user being able to change channel banner is attributed to @maria.nunez
  • Reason: The output does not mention the specific bug about an end user being able to change the channel banner, nor does it attribute that bug to @maria.nunez. It only requests the bug reports and provides a blank template.

7. TestDirectMessageConversations/[openai]_bot_dm_tool_introspection

  • Score: 0.50
  • Rubric: mentions Github and refers to the documentation
  • Reason: The output refers to documentation (docs.mattermost.com) but does not mention GitHub anywhere, so it does not satisfy the rubric requirement to mention GitHub and refer to the documentation.

Anthropic

⚠️ Overall: 21/28 tests passed (75.0%)

Provider Total Passed Failed Pass Rate
⚠️ ANTHROPIC 28 21 7 75.0%

❌ Failed Evaluations

Show 7 failures

ANTHROPIC

1. TestReactEval/[anthropic]_react_cat_message

  • Score: 0.00
  • Rubric: The word/emoji is a cat emoji or a heart/love emoji
  • Reason: The output is the text string "heart_eyes_cat", not an actual cat emoji (e.g., 😺) or a heart/love emoji (e.g., ❤️).

2. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: is a list of bugs
  • Reason: The output does not provide any bugs or a list of bugs. It states inability to access trackers and suggests where to look, offering to format bugs if provided.

3. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: includes a description of each bug
  • Reason: The output states it cannot access bug trackers and suggests where to look, but it does not provide any bug descriptions. Therefore it does not include a description of each bug.

4. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes each bug to a user
  • Reason: The output does not list any bugs and therefore does not attribute each bug to a user; it only states it cannot access trackers and suggests where to look.

5. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes the bug about trying to save without a color and the save button not doing anything to @maria.nunez
  • Reason: The output does not mention the specific bug about saving without a color, does not mention the save button doing nothing, and does not attribute anything to @maria.nunez. It only states it cannot access trackers and suggests where to look.

6. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: the bug about the end user being able to change channel banner is attributed to @maria.nunez
  • Reason: The output does not mention the specific bug about an end user being able to change the channel banner, nor does it attribute that bug to @maria.nunez. It only states it cannot access bug trackers and suggests where to look.

7. TestDirectMessageConversations/[anthropic]_bot_dm_tool_introspection

  • Score: 0.00
  • Rubric: mentions Github and refers to the documentation
  • Reason: The output refers to documentation (docs.mattermost.com) but does not mention GitHub anywhere. Since the rubric requires both mentioning GitHub and referring to the documentation, it fails.

This comment was automatically generated by the eval CI pipeline.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@conversations/conversations.go`:
- Around line 251-258: Apply the remote MCP license check to the
allToolsAutoRunEverywhere batch predicate as well as the existing
individual-tool path. Ensure an unlicensed remote MCP initial batch cannot
qualify for automatic execution, and add coverage for this unlicensed
initial-batch scenario.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: b9b21787-19b7-42c9-ae07-2940e7528478

📥 Commits

Reviewing files that changed from the base of the PR and between 5de1bfc and d149fd3.

📒 Files selected for processing (9)
  • conversations/ask_user_question_flow_test.go
  • conversations/conversations.go
  • conversations/dynamic_mcp_workflow_test.go
  • conversations/tool_approval.go
  • conversations/tool_approval_license_test.go
  • conversations/tool_policy_test.go
  • docs/admin_guide.md
  • docs/upgrading_to_2.0.md
  • webapp/src/i18n/en.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • webapp/src/i18n/en.json
  • docs/upgrading_to_2.0.md
  • docs/admin_guide.md

Comment thread conversations/conversations.go Outdated
…er config UI when unlicensed

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
conversations/bot_channel_tool_filter_test.go (1)

91-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Backward-compatible parameterization; duplicated license-mock logic noted for consolidation.

Delegating the default (licensed=true) preserves existing callers' behaviour. The license-conditional mock block (Lines 103-107) duplicates the same logic in tool_approval_license_test.go; see the consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@conversations/bot_channel_tool_filter_test.go` around lines 91 - 107,
Consolidate the duplicated license-mock setup used by
newChannelFollowUpTestBuilderWithLicense with the existing helper or shared
logic from tool_approval_license_test.go. Preserve
newChannelFollowUpTestBuilder’s default licensed=true behavior and ensure
licensed and unlicensed cases continue returning the corresponding mock License
values.
api/api_agents_test.go (1)

85-93: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the model.LicenseShortSkuEnterprise constant instead of the literal "enterprise".

Every other license mock in this PR (tool_approval_license_test.go, bot_channel_tool_filter_test.go, single_build_test.go, api_test.go) uses model.LicenseShortSkuEnterprise. The raw string here is a minor inconsistency that could silently drift if the SKU value ever changes upstream.

♻️ Proposed fix
 func mockLicensed(mockAPI *plugintest.API) {
 	overrideLicenseMocks(mockAPI, &model.License{
 		Features: &model.Features{
 			LDAP: model.NewPointer(true),
 		},
-		SkuShortName: "enterprise",
+		SkuShortName: model.LicenseShortSkuEnterprise,
 	})
 }

Please confirm model.LicenseShortSkuEnterprise still resolves to "enterprise" in the pinned mattermost/server/public version used by this repo.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/api_agents_test.go` around lines 85 - 93, Update mockLicensed to use
model.LicenseShortSkuEnterprise for License.SkuShortName instead of the literal
"enterprise", preserving the existing enterprise license mock behavior and
aligning it with the pinned Mattermost model constant.
conversations/tool_approval_license_test.go (2)

71-108: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate license-mock boilerplate vs. bot_channel_tool_filter_test.go.

The if licensed {...} else {...} block mocking GetLicense/GetConfig (Lines 78-83) is identical to newChannelFollowUpTestBuilderWithLicense in conversations/bot_channel_tool_filter_test.go. See the consolidated comment below for a suggested shared helper.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@conversations/tool_approval_license_test.go` around lines 71 - 108,
Consolidate the duplicated license/config mock setup in toolLicenseTestBuilder
with the existing newChannelFollowUpTestBuilderWithLicense helper from
bot_channel_tool_filter_test.go. Reuse or extract a shared helper for GetConfig
and GetLicense behavior, preserving the licensed and unlicensed responses while
removing the local if/else boilerplate.

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated license-mock block into a shared test helper. Both files mock GetLicense/GetConfig with the identical if licensed {...Enterprise...} else {...nil...} block; the shared root cause is the lack of a common helper for license-state mocking in the conversations test package.

  • conversations/tool_approval_license_test.go#L71-108: extract the GetConfig/GetLicense conditional (Lines 78-83) into a shared helper (e.g., mockLicenseState(mockAPI *plugintest.API, licensed bool)) and call it here.
  • conversations/bot_channel_tool_filter_test.go#L91-107: replace the identical conditional (Lines 103-107) with a call to the same shared helper.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@conversations/tool_approval_license_test.go` at line 1, Extract the
duplicated GetConfig/GetLicense licensed-state conditional from the tests into a
shared conversations test helper such as mockLicenseState, accepting
*plugintest.API and a licensed boolean. Replace the inline blocks in the license
test and bot channel tool filter test with calls to this helper, preserving both
Enterprise license and nil-license behaviors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@webapp/src/components/system_console/mcp_servers.tsx`:
- Around line 595-598: Update the EnterpriseChip usage in the remote MCP server
section to pass a localized plan-neutral title such as “Licensed feature”
through its title prop, replacing the default “Enterprise feature” wording while
preserving the existing text and subtext.

---

Nitpick comments:
In `@api/api_agents_test.go`:
- Around line 85-93: Update mockLicensed to use model.LicenseShortSkuEnterprise
for License.SkuShortName instead of the literal "enterprise", preserving the
existing enterprise license mock behavior and aligning it with the pinned
Mattermost model constant.

In `@conversations/bot_channel_tool_filter_test.go`:
- Around line 91-107: Consolidate the duplicated license-mock setup used by
newChannelFollowUpTestBuilderWithLicense with the existing helper or shared
logic from tool_approval_license_test.go. Preserve
newChannelFollowUpTestBuilder’s default licensed=true behavior and ensure
licensed and unlicensed cases continue returning the corresponding mock License
values.

In `@conversations/tool_approval_license_test.go`:
- Around line 71-108: Consolidate the duplicated license/config mock setup in
toolLicenseTestBuilder with the existing
newChannelFollowUpTestBuilderWithLicense helper from
bot_channel_tool_filter_test.go. Reuse or extract a shared helper for GetConfig
and GetLicense behavior, preserving the licensed and unlicensed responses while
removing the local if/else boilerplate.
- Line 1: Extract the duplicated GetConfig/GetLicense licensed-state conditional
from the tests into a shared conversations test helper such as mockLicenseState,
accepting *plugintest.API and a licensed boolean. Replace the inline blocks in
the license test and bot channel tool filter test with calls to this helper,
preserving both Enterprise license and nil-license behaviors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 343e1a4e-1f14-4ccb-bc28-c71dae63fcc1

📥 Commits

Reviewing files that changed from the base of the PR and between d149fd3 and 325d2b0.

📒 Files selected for processing (15)
  • api/api_agents_test.go
  • api/api_test.go
  • conversations/ask_user_question_flow_test.go
  • conversations/bot_channel_tool_filter_test.go
  • conversations/single_build_test.go
  • conversations/tool_approval.go
  • conversations/tool_approval_license_test.go
  • docs/admin_guide.md
  • llmcontext/llm_context.go
  • llmcontext/llm_context_license_test.go
  • llmcontext/llm_context_test.go
  • mcp/vetted_tools.go
  • webapp/src/components/system_console/mcp_servers.test.tsx
  • webapp/src/components/system_console/mcp_servers.tsx
  • webapp/src/i18n/en.json
💤 Files with no reviewable changes (1)
  • webapp/src/i18n/en.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • conversations/tool_approval.go
  • conversations/ask_user_question_flow_test.go

Comment thread webapp/src/components/system_console/mcp_servers.tsx
… helpers

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
@crspeller
crspeller requested a review from nickmisasi July 28, 2026 11:58
@crspeller
crspeller merged commit 9df85e2 into master Jul 28, 2026
31 checks passed
@crspeller
crspeller deleted the cursor/embedded-mcp-license-gate-2922 branch July 28, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants