@automattic/mcp-wordpress-remote 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/proxy.js +81 -9
- package/package.json +1 -1
package/dist/proxy.js
CHANGED
|
@@ -34,6 +34,10 @@ var CONFIG = {
|
|
|
34
34
|
// Resource Indicators (RFC 8707)
|
|
35
35
|
OAUTH_RESOURCE_INDICATOR: process.env.OAUTH_RESOURCE_INDICATOR !== "false",
|
|
36
36
|
// Resource parameter support
|
|
37
|
+
// OAuth Scopes Configuration
|
|
38
|
+
// OAUTH_SCOPES: Comma-separated list of OAuth scopes (e.g., "read,write" or "global")
|
|
39
|
+
// If empty, uses defaults: "global" for WordPress.com, "read,write" for self-hosted
|
|
40
|
+
OAUTH_SCOPES: process.env.OAUTH_SCOPES || "",
|
|
37
41
|
// Timeout Configuration (in milliseconds)
|
|
38
42
|
OAUTH_TIMEOUT: 3e4,
|
|
39
43
|
// 30 seconds
|
|
@@ -52,6 +56,12 @@ var CONFIG = {
|
|
|
52
56
|
// Environment
|
|
53
57
|
NODE_ENV: process.env.NODE_ENV || "development"
|
|
54
58
|
};
|
|
59
|
+
function parseOAuthScopes(envScopes, defaultScopes) {
|
|
60
|
+
if (!envScopes || envScopes.trim() === "") {
|
|
61
|
+
return defaultScopes;
|
|
62
|
+
}
|
|
63
|
+
return envScopes.split(",").map((scope) => scope.trim()).filter((scope) => scope.length > 0);
|
|
64
|
+
}
|
|
55
65
|
function isWordPressComSite(url) {
|
|
56
66
|
try {
|
|
57
67
|
const siteUrl = new URL(url);
|
|
@@ -64,15 +74,18 @@ function isWordPressComSite(url) {
|
|
|
64
74
|
}
|
|
65
75
|
function getRecommendedOAuthConfig(siteUrl) {
|
|
66
76
|
if (isWordPressComSite(siteUrl)) {
|
|
77
|
+
const defaultScopes = ["global"];
|
|
67
78
|
return {
|
|
68
79
|
flowType: "implicit",
|
|
69
80
|
usePKCE: false,
|
|
70
81
|
useResourceIndicator: false,
|
|
71
82
|
authorizationEndpoint: "https://public-api.wordpress.com/oauth2/authorize",
|
|
72
83
|
tokenEndpoint: "https://public-api.wordpress.com/oauth2/token",
|
|
84
|
+
scopes: parseOAuthScopes(CONFIG.OAUTH_SCOPES, defaultScopes),
|
|
73
85
|
description: "WordPress.com OAuth2 (compatible mode)"
|
|
74
86
|
};
|
|
75
87
|
} else {
|
|
88
|
+
const defaultScopes = ["read", "write"];
|
|
76
89
|
return {
|
|
77
90
|
flowType: "authorization_code",
|
|
78
91
|
usePKCE: true,
|
|
@@ -81,6 +94,7 @@ function getRecommendedOAuthConfig(siteUrl) {
|
|
|
81
94
|
// Will be discovered
|
|
82
95
|
tokenEndpoint: void 0,
|
|
83
96
|
// Will be discovered
|
|
97
|
+
scopes: parseOAuthScopes(CONFIG.OAUTH_SCOPES, defaultScopes),
|
|
84
98
|
description: "MCP-compliant OAuth 2.1"
|
|
85
99
|
};
|
|
86
100
|
}
|
|
@@ -707,9 +721,11 @@ var AUTHORIZATION_CODE_HTML = `
|
|
|
707
721
|
document.getElementById('details').textContent = message;
|
|
708
722
|
}
|
|
709
723
|
|
|
710
|
-
//
|
|
724
|
+
// Handle both OAuth 2.1 authorization code flow and implicit flow
|
|
711
725
|
const urlParams = new URLSearchParams(window.location.search);
|
|
726
|
+
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
|
712
727
|
|
|
728
|
+
// Check for authorization code first (OAuth 2.1 flow)
|
|
713
729
|
if (urlParams.has('code')) {
|
|
714
730
|
const authData = {
|
|
715
731
|
code: urlParams.get('code'),
|
|
@@ -745,13 +761,63 @@ var AUTHORIZATION_CODE_HTML = `
|
|
|
745
761
|
displayStatus('\u274C Error completing authorization', 'error');
|
|
746
762
|
displayDetails(error.message + '. Please try again.');
|
|
747
763
|
});
|
|
748
|
-
}
|
|
764
|
+
}
|
|
765
|
+
// Check for access token in URL fragment (implicit flow - WordPress.com)
|
|
766
|
+
else if (hashParams.has('access_token')) {
|
|
767
|
+
const tokens = {
|
|
768
|
+
access_token: hashParams.get('access_token'),
|
|
769
|
+
token_type: hashParams.get('token_type') || 'Bearer',
|
|
770
|
+
expires_in: hashParams.get('expires_in') ? parseInt(hashParams.get('expires_in')) : 3600,
|
|
771
|
+
scope: hashParams.get('scope'),
|
|
772
|
+
state: hashParams.get('state'),
|
|
773
|
+
obtained_at: Date.now()
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
// Send tokens to server for storage
|
|
777
|
+
fetch('/oauth/tokens', {
|
|
778
|
+
method: 'POST',
|
|
779
|
+
headers: {
|
|
780
|
+
'Content-Type': 'application/json'
|
|
781
|
+
},
|
|
782
|
+
body: JSON.stringify(tokens)
|
|
783
|
+
})
|
|
784
|
+
.then(response => {
|
|
785
|
+
if (response.ok) {
|
|
786
|
+
displayStatus('\u2705 Authorization successful!', 'success');
|
|
787
|
+
displayDetails('WordPress.com OAuth authentication completed. You can now close this window.');
|
|
788
|
+
// Auto-close after 3 seconds
|
|
789
|
+
setTimeout(() => {
|
|
790
|
+
displayDetails('Closing window...');
|
|
791
|
+
setTimeout(() => window.close(), 1000);
|
|
792
|
+
}, 3000);
|
|
793
|
+
} else {
|
|
794
|
+
return response.json().then(err => {
|
|
795
|
+
throw new Error(err.error || 'Failed to store access token');
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
})
|
|
799
|
+
.catch(error => {
|
|
800
|
+
displayStatus('\u274C Error completing authorization', 'error');
|
|
801
|
+
displayDetails(error.message + '. Please try again.');
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
// Check for errors in query parameters
|
|
805
|
+
else if (urlParams.has('error')) {
|
|
749
806
|
const error = urlParams.get('error');
|
|
750
807
|
const errorDescription = urlParams.get('error_description');
|
|
751
808
|
displayStatus('\u274C Authorization failed', 'error');
|
|
752
809
|
displayDetails(\`Error: \${error}\${errorDescription ? ' - ' + errorDescription : ''}\`);
|
|
753
|
-
}
|
|
754
|
-
|
|
810
|
+
}
|
|
811
|
+
// Check for errors in URL fragment (implicit flow errors)
|
|
812
|
+
else if (hashParams.has('error')) {
|
|
813
|
+
const error = hashParams.get('error');
|
|
814
|
+
const errorDescription = hashParams.get('error_description');
|
|
815
|
+
displayStatus('\u274C Authorization failed', 'error');
|
|
816
|
+
displayDetails(\`Error: \${error}\${errorDescription ? ' - ' + errorDescription : ''}\`);
|
|
817
|
+
}
|
|
818
|
+
// No authorization code or access token found
|
|
819
|
+
else {
|
|
820
|
+
displayStatus('\u274C No authorization code or access token received', 'error');
|
|
755
821
|
displayDetails('Please try the authorization process again.');
|
|
756
822
|
}
|
|
757
823
|
</script>
|
|
@@ -889,15 +955,17 @@ var MCPOAuthProvider = class {
|
|
|
889
955
|
// Discovered metadata
|
|
890
956
|
this.authServerMetadata = null;
|
|
891
957
|
this.resourceMetadata = null;
|
|
958
|
+
const serverUrl = options.serverUrl || CONFIG.WP_API_URL;
|
|
959
|
+
const recommendedConfig = getRecommendedOAuthConfig(serverUrl);
|
|
892
960
|
this.config = {
|
|
893
|
-
serverUrl
|
|
894
|
-
resource: generateCanonicalResourceURI(
|
|
961
|
+
serverUrl,
|
|
962
|
+
resource: generateCanonicalResourceURI(serverUrl),
|
|
895
963
|
responseType: "code",
|
|
896
964
|
// OAuth 2.1 uses authorization code flow
|
|
897
965
|
usePKCE: true,
|
|
898
966
|
// PKCE is required for OAuth 2.1
|
|
899
967
|
redirectUri: `http://${CONFIG.OAUTH_HOST}:${CONFIG.OAUTH_CALLBACK_PORT}/oauth/callback`,
|
|
900
|
-
scopes: options.scopes ||
|
|
968
|
+
scopes: options.scopes || recommendedConfig.scopes,
|
|
901
969
|
clientId: options.clientId || CONFIG.WP_OAUTH_CLIENT_ID,
|
|
902
970
|
callbackPort: CONFIG.OAUTH_CALLBACK_PORT,
|
|
903
971
|
host: CONFIG.OAUTH_HOST,
|
|
@@ -1260,6 +1328,7 @@ import { EventEmitter as EventEmitter2 } from "node:events";
|
|
|
1260
1328
|
var WP_PERSISTENT_CONFIG = {
|
|
1261
1329
|
authorizeEndpoint: "/wp-admin/admin.php?page=mcp-oauth-authorize",
|
|
1262
1330
|
scopes: ["read", "write"],
|
|
1331
|
+
// Default for self-hosted, will be overridden for WordPress.com
|
|
1263
1332
|
callbackPort: CONFIG.OAUTH_CALLBACK_PORT,
|
|
1264
1333
|
host: CONFIG.OAUTH_HOST
|
|
1265
1334
|
};
|
|
@@ -1270,7 +1339,9 @@ var PersistentWPOAuthClientProvider = class {
|
|
|
1270
1339
|
const recommendedConfig = getRecommendedOAuthConfig(options.serverUrl || "");
|
|
1271
1340
|
this.options = {
|
|
1272
1341
|
...WP_PERSISTENT_CONFIG,
|
|
1273
|
-
...options
|
|
1342
|
+
...options,
|
|
1343
|
+
// Use recommended scopes for the site type
|
|
1344
|
+
scopes: options.scopes || recommendedConfig.scopes
|
|
1274
1345
|
};
|
|
1275
1346
|
if (isWpCom && recommendedConfig.authorizationEndpoint) {
|
|
1276
1347
|
this.options.authorizeEndpoint = recommendedConfig.authorizationEndpoint;
|
|
@@ -1911,10 +1982,11 @@ async function getOAuthTokens() {
|
|
|
1911
1982
|
const shouldUseMCPFlow = !isWPCom && CONFIG.OAUTH_FLOW_TYPE === "authorization_code" && CONFIG.OAUTH_USE_PKCE;
|
|
1912
1983
|
if (shouldUseMCPFlow) {
|
|
1913
1984
|
if (!mcpOAuthProvider) {
|
|
1985
|
+
const recommendedConfig2 = getRecommendedOAuthConfig(serverUrl);
|
|
1914
1986
|
mcpOAuthProvider = new MCPOAuthProvider({
|
|
1915
1987
|
serverUrl,
|
|
1916
1988
|
clientId: CONFIG.WP_OAUTH_CLIENT_ID,
|
|
1917
|
-
scopes:
|
|
1989
|
+
scopes: recommendedConfig2.scopes
|
|
1918
1990
|
});
|
|
1919
1991
|
}
|
|
1920
1992
|
logger.auth("Using MCP-compliant OAuth 2.1 authorization code flow with PKCE");
|