Skip to content

Commit 9158dde

Browse files
authored
Merge pull request #1163 from Kit/abilities-api-gate-by-plan
Abilities API: Gate by Plan
2 parents 75ddcb7 + e740f48 commit 9158dde

5 files changed

Lines changed: 282 additions & 5 deletions

File tree

admin/section/class-convertkit-admin-section-mcp.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,27 @@ public function documentation_url() {
241241

242242
}
243243

244+
/**
245+
* Renders the upgrade CTA when the connected Kit account is on
246+
* the free plan.
247+
*
248+
* @since 3.4.0
249+
*/
250+
public function output_upgrade_required_message() {
251+
252+
?>
253+
<p>
254+
<?php esc_html_e( 'The Kit WordPress MCP is available on paid Kit plans. Upgrade your Kit account to connect AI clients to your WordPress site.', 'convertkit' ); ?>
255+
</p>
256+
<p>
257+
<a href="https://app.kit.com/account_settings/billing" class="button button-primary" target="_blank">
258+
<?php esc_html_e( 'Upgrade Kit Account', 'convertkit' ); ?>
259+
</a>
260+
</p>
261+
<?php
262+
263+
}
264+
244265
/**
245266
* Renders the input for the Enable setting.
246267
*
@@ -250,6 +271,16 @@ public function documentation_url() {
250271
*/
251272
public function enabled_callback( $args ) {
252273

274+
// If the user doesn't have a paid plan, show the upgrade required message.
275+
$account = new ConvertKit_Resource_Account();
276+
if ( ! $account->is_paid_plan() ) {
277+
// Disable saving settings.
278+
$this->save_disabled = true;
279+
280+
$this->output_upgrade_required_message();
281+
return;
282+
}
283+
253284
// Output field.
254285
$this->output_checkbox_field(
255286
$args['name'],

includes/class-convertkit-settings-mcp.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,22 @@ public function get() {
6565
}
6666

6767
/**
68-
* Returns whether the MCP server is enabled.
68+
* Returns whether the user has access to MCP via a paid plan,
69+
* and if so whether the MCP server is enabled in the Plugin's settings.
6970
*
7071
* @since 3.4.0
7172
*
7273
* @return bool
7374
*/
7475
public function enabled() {
7576

77+
// Bail if the connected Kit account isn't on a paid plan.
78+
// This queries the cached account details, so no live API call is made.
79+
$account = new ConvertKit_Resource_Account();
80+
if ( ! $account->is_paid_plan() ) {
81+
return false;
82+
}
83+
7684
return ( $this->settings['enabled'] === 'on' ? true : false );
7785

7886
}

includes/mcp/class-convertkit-mcp.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,12 @@ public function register_abilities() {
259259
*/
260260
public function register_mcp_server( $adapter ) {
261261

262+
// Bail if the MCP server isn't enabled.
263+
$settings = new ConvertKit_Settings_MCP();
264+
if ( ! $settings->enabled() ) {
265+
return;
266+
}
267+
262268
// Get abilities.
263269
$abilities = convertkit_get_abilities();
264270

tests/EndToEnd/general/plugin-screens/PluginSettingsMCPCest.php

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ public function _before(EndToEndTester $I)
2222
{
2323
// Activate Kit Plugin.
2424
$I->activateKitPlugin($I);
25-
26-
// Setup Plugin.
27-
$I->setupKitPlugin($I);
2825
}
2926

3027
/**
@@ -36,8 +33,20 @@ public function _before(EndToEndTester $I)
3633
*/
3734
public function testEnableAndDisableMCPServerSetting(EndToEndTester $I)
3835
{
36+
// Simulate a Kit account that is on a paid plan.
37+
$I->setupKitPlugin($I);
38+
$I->haveOptionInDatabase(
39+
'convertkit_account',
40+
[
41+
'account' => [
42+
'plan_type' => 'creator_pro',
43+
],
44+
]
45+
);
46+
3947
// Check that the MCP server is not registered.
40-
$I->doesNotHaveRoute($I, '/kit-mcp');
48+
$I->doesNotHaveRoute($I, '/kit/mcp');
49+
$I->doesNotHaveRoute($I, '/kit/mcp/v1');
4150

4251
// Go to the Plugin's MCP Screen.
4352
$I->loadKitSettingsMCPScreen($I);
@@ -88,6 +97,17 @@ public function testEnableAndDisableMCPServerSetting(EndToEndTester $I)
8897
*/
8998
public function testGenerateAndRevokeApplicationPassword(EndToEndTester $I)
9099
{
100+
// Simulate a Kit account that is on a paid plan.
101+
$I->setupKitPlugin($I);
102+
$I->haveOptionInDatabase(
103+
'convertkit_account',
104+
[
105+
'account' => [
106+
'plan_type' => 'creator_pro',
107+
],
108+
]
109+
);
110+
91111
// Go to the Plugin's MCP Screen.
92112
$I->loadKitSettingsMCPScreen($I);
93113

@@ -158,6 +178,86 @@ public function testGenerateAndRevokeApplicationPassword(EndToEndTester $I)
158178
$I->waitForElementNotVisible('#convertkit-settings-mcp-revoke-application-password');
159179
}
160180

181+
/**
182+
* Tests that a free-plan Kit account sees the upgrade CTA on the MCP tab
183+
* instead of the enable / connect UI, and that the MCP REST route is not
184+
* registered even when the enabled setting is on.
185+
*
186+
* @since 3.4.0
187+
*
188+
* @param EndToEndTester $I Tester.
189+
*/
190+
public function testFreePlanShowsUpgradeCTA(EndToEndTester $I)
191+
{
192+
// Simulate a Kit account that is on the free plan.
193+
$I->setupKitPluginFakeAPIKey($I);
194+
$I->setupKitPluginResources($I);
195+
$I->haveOptionInDatabase(
196+
'convertkit_account',
197+
[
198+
'account' => [
199+
'plan_type' => 'free',
200+
],
201+
]
202+
);
203+
204+
// Enable MCP server.
205+
$I->haveOptionInDatabase(
206+
'_wp_convertkit_settings_mcp',
207+
[
208+
'enabled' => 'on',
209+
]
210+
);
211+
212+
// Load the MCP settings tab.
213+
$I->loadKitSettingsMCPScreen($I);
214+
215+
// Assert that the upgrade CTA is shown.
216+
$I->see('The Kit WordPress MCP is available on paid Kit plans. Upgrade your Kit account to connect AI clients to your WordPress site.');
217+
$I->seeLink('Upgrade Kit Account');
218+
219+
// Assert no option to enable/disable the MCP server are shown.
220+
$I->dontSeeElement('#enabled');
221+
$I->dontSee('Create Application Password');
222+
223+
// Assert that the MCP server is not registered.
224+
$I->doesNotHaveRoute($I, '/kit/mcp');
225+
$I->doesNotHaveRoute($I, '/kit/mcp/v1');
226+
}
227+
228+
/**
229+
* Tests that a paid-plan Kit account sees the enable UI on the MCP tab
230+
* (i.e. the upgrade CTA is not shown).
231+
*
232+
* @since 3.4.0
233+
*
234+
* @param EndToEndTester $I Tester.
235+
*/
236+
public function testPaidPlanShowsEnableUI(EndToEndTester $I)
237+
{
238+
// Simulate a Kit account that is on a paid plan.
239+
$I->setupKitPlugin($I);
240+
$I->setupKitPluginResources($I);
241+
$I->haveOptionInDatabase(
242+
'convertkit_account',
243+
[
244+
'account' => [
245+
'plan_type' => 'creator_pro',
246+
],
247+
]
248+
);
249+
250+
// Load the MCP settings tab.
251+
$I->loadKitSettingsMCPScreen($I);
252+
253+
// The upgrade CTA should not be shown.
254+
$I->dontSee('The Kit WordPress MCP is available on paid Kit plans. Upgrade your Kit account to connect AI clients to your WordPress site.');
255+
$I->dontSeeLink('Upgrade Kit Account');
256+
257+
// The Enable checkbox should be visible.
258+
$I->seeElement('#enabled');
259+
}
260+
161261
/**
162262
* Deactivate and reset Plugin(s) after each test, if the test passes.
163263
* We don't use _after, as this would provide a screenshot of the Plugin
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
3+
namespace Tests;
4+
5+
use lucatume\WPBrowser\TestCase\WPTestCase;
6+
7+
/**
8+
* Tests for the ConvertKit_Settings_MCP class, in particular that enabled()
9+
* is the single source of truth combining the toggle setting and the cached
10+
* account plan.
11+
*
12+
* @since 3.4.0
13+
*/
14+
class SettingsMCPTest extends WPTestCase
15+
{
16+
/**
17+
* The testing implementation.
18+
*
19+
* @var \WpunitTester.
20+
*/
21+
protected $tester;
22+
23+
/**
24+
* Performs actions before each test.
25+
*
26+
* @since 3.4.0
27+
*/
28+
public function setUp(): void
29+
{
30+
parent::setUp();
31+
activate_plugins('convertkit/wp-convertkit.php');
32+
}
33+
34+
/**
35+
* Performs actions after each test.
36+
*
37+
* @since 3.4.0
38+
*/
39+
public function tearDown(): void
40+
{
41+
delete_option(\ConvertKit_Settings_MCP::SETTINGS_NAME);
42+
delete_option('convertkit_account');
43+
deactivate_plugins('convertkit/wp-convertkit.php');
44+
parent::tearDown();
45+
}
46+
47+
/**
48+
* Test that enabled() returns false when the MCP toggle is off, regardless
49+
* of the cached plan type.
50+
*
51+
* @since 3.4.0
52+
*/
53+
public function testEnabledFalseWhenToggleOff()
54+
{
55+
update_option(\ConvertKit_Settings_MCP::SETTINGS_NAME, [ 'enabled' => '' ]);
56+
update_option(
57+
'convertkit_account',
58+
[ 'account' => [ 'plan_type' => 'creator_pro' ] ]
59+
);
60+
61+
$settings = new \ConvertKit_Settings_MCP();
62+
$this->assertSame(false, $settings->enabled());
63+
}
64+
65+
/**
66+
* Test that enabled() returns false when the toggle is on but no account is
67+
* cached (fail closed).
68+
*
69+
* @since 3.4.0
70+
*/
71+
public function testEnabledFalseWhenToggleOnAndNoAccountCache()
72+
{
73+
update_option(\ConvertKit_Settings_MCP::SETTINGS_NAME, [ 'enabled' => 'on' ]);
74+
delete_option('convertkit_account');
75+
76+
$settings = new \ConvertKit_Settings_MCP();
77+
$this->assertSame(false, $settings->enabled());
78+
}
79+
80+
/**
81+
* Test that enabled() returns false when the toggle is on but the cached
82+
* plan is free.
83+
*
84+
* @since 3.4.0
85+
*/
86+
public function testEnabledFalseWhenToggleOnAndFreePlan()
87+
{
88+
update_option(\ConvertKit_Settings_MCP::SETTINGS_NAME, [ 'enabled' => 'on' ]);
89+
update_option(
90+
'convertkit_account',
91+
[ 'account' => [ 'plan_type' => 'free' ] ]
92+
);
93+
94+
$settings = new \ConvertKit_Settings_MCP();
95+
$this->assertSame(false, $settings->enabled());
96+
}
97+
98+
/**
99+
* Test that enabled() returns true when the toggle is on and the cached
100+
* plan is a paid plan.
101+
*
102+
* @since 3.4.0
103+
*/
104+
public function testEnabledTrueWhenToggleOnAndPaidPlan()
105+
{
106+
update_option(\ConvertKit_Settings_MCP::SETTINGS_NAME, [ 'enabled' => 'on' ]);
107+
update_option(
108+
'convertkit_account',
109+
[ 'account' => [ 'plan_type' => 'creator' ] ]
110+
);
111+
112+
$settings = new \ConvertKit_Settings_MCP();
113+
$this->assertSame(true, $settings->enabled());
114+
}
115+
116+
/**
117+
* Test that enabled() returns true for creator_pro plans.
118+
*
119+
* @since 3.4.0
120+
*/
121+
public function testEnabledTrueForCreatorProPlan()
122+
{
123+
update_option(\ConvertKit_Settings_MCP::SETTINGS_NAME, [ 'enabled' => 'on' ]);
124+
update_option(
125+
'convertkit_account',
126+
[ 'account' => [ 'plan_type' => 'creator_pro' ] ]
127+
);
128+
129+
$settings = new \ConvertKit_Settings_MCP();
130+
$this->assertSame(true, $settings->enabled());
131+
}
132+
}

0 commit comments

Comments
 (0)