@gravitykit/block-mcp 2.0.1 → 2.1.0
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/index.cjs +311 -195
- package/package.json +8 -4
- package/src/__tests__/coerce.test.ts +57 -0
- package/src/__tests__/fixtures/error-envelopes.ts +19 -7
- package/src/__tests__/integration/error-envelopes.test.ts +2 -2
- package/src/__tests__/tools/discovery/list_patterns.test.ts +25 -6
- package/src/__tests__/tools/mutate/edit_block_tree.test.ts +53 -0
- package/src/__tests__/tools/patterns/insert_pattern.test.ts +16 -0
- package/src/__tests__/tools/posts/update_post.test.ts +14 -0
- package/src/__tests__/tools/read/get_block.test.ts +35 -0
- package/src/__tests__/tools/read/get_page_blocks.test.ts +18 -0
- package/src/__tests__/tools/write/delete_block.test.ts +18 -0
- package/src/__tests__/tools/write/insert_blocks.test.ts +21 -0
- package/src/__tests__/tools/write/replace_block_range.test.ts +71 -0
- package/src/__tests__/tools/write/rewrite_post_blocks.test.ts +39 -0
- package/src/__tests__/tools/write/update_block.test.ts +16 -0
- package/src/__tests__/tools/write/update_blocks.test.ts +21 -0
- package/src/__tests__/tools/yoast/yoast_get_seo.test.ts +11 -3
- package/src/__tests__/tools/yoast/yoast_update_seo.test.ts +16 -0
- package/src/__tests__/unit/enrichers/cbp-enricher.test.ts +21 -0
- package/src/__tests__/unit/error-translator/translate-wp-error.test.ts +100 -29
- package/src/__tests__/unit/instructions.test.ts +3 -3
- package/src/__tests__/unit/preferences/enrich-pattern-list.test.ts +26 -10
- package/src/__tests__/unit/rest-url.test.ts +23 -0
- package/src/client.ts +53 -18
- package/src/coerce.ts +41 -0
- package/src/config.ts +96 -0
- package/src/connect.ts +17 -3
- package/src/enrichers.ts +6 -2
- package/src/error-translator.ts +62 -10
- package/src/index.ts +35 -27
- package/src/instructions.ts +3 -3
- package/src/preferences.ts +56 -43
- package/src/rest-url.ts +18 -0
- package/src/tools/discovery.ts +10 -14
- package/src/tools/mutate.ts +18 -12
- package/src/tools/patterns.ts +3 -2
- package/src/tools/posts.ts +26 -26
- package/src/tools/read.ts +7 -6
- package/src/tools/write.ts +26 -31
- package/src/tools/yoast.ts +30 -31
- package/src/types.ts +23 -13
package/dist/index.cjs
CHANGED
|
@@ -7,7 +7,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
9
|
var __commonJS = (cb, mod) => function __require() {
|
|
10
|
-
|
|
10
|
+
try {
|
|
11
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw mod = 0, e;
|
|
14
|
+
}
|
|
11
15
|
};
|
|
12
16
|
var __export = (target, all4) => {
|
|
13
17
|
for (var name in all4)
|
|
@@ -16854,6 +16858,9 @@ var require_form_data = __commonJS({
|
|
|
16854
16858
|
var setToStringTag = require_es_set_tostringtag();
|
|
16855
16859
|
var hasOwn = require_hasown();
|
|
16856
16860
|
var populate = require_populate();
|
|
16861
|
+
function escapeHeaderParam(str) {
|
|
16862
|
+
return String(str).replace(/\r/g, "%0D").replace(/\n/g, "%0A").replace(/"/g, "%22");
|
|
16863
|
+
}
|
|
16857
16864
|
function FormData3(options) {
|
|
16858
16865
|
if (!(this instanceof FormData3)) {
|
|
16859
16866
|
return new FormData3(options);
|
|
@@ -16943,7 +16950,7 @@ var require_form_data = __commonJS({
|
|
|
16943
16950
|
var contents = "";
|
|
16944
16951
|
var headers = {
|
|
16945
16952
|
// add custom disposition as third element or keep it two elements if not
|
|
16946
|
-
"Content-Disposition": ["form-data", 'name="' + field + '"'].concat(contentDisposition || []),
|
|
16953
|
+
"Content-Disposition": ["form-data", 'name="' + escapeHeaderParam(field) + '"'].concat(contentDisposition || []),
|
|
16947
16954
|
// if no content type. allow it to be empty array
|
|
16948
16955
|
"Content-Type": [].concat(contentType || [])
|
|
16949
16956
|
};
|
|
@@ -16977,7 +16984,7 @@ var require_form_data = __commonJS({
|
|
|
16977
16984
|
filename = path2.basename(value.client._httpMessage.path || "");
|
|
16978
16985
|
}
|
|
16979
16986
|
if (filename) {
|
|
16980
|
-
return 'filename="' + filename + '"';
|
|
16987
|
+
return 'filename="' + escapeHeaderParam(filename) + '"';
|
|
16981
16988
|
}
|
|
16982
16989
|
};
|
|
16983
16990
|
FormData3.prototype._getContentType = function(value, options) {
|
|
@@ -35208,7 +35215,7 @@ var StdioServerTransport = class {
|
|
|
35208
35215
|
// package.json
|
|
35209
35216
|
var package_default = {
|
|
35210
35217
|
name: "@gravitykit/block-mcp",
|
|
35211
|
-
version: "2.0
|
|
35218
|
+
version: "2.1.0",
|
|
35212
35219
|
description: "MCP server for WordPress block-level content management with preference-aware editing",
|
|
35213
35220
|
main: "dist/index.cjs",
|
|
35214
35221
|
bin: {
|
|
@@ -35225,6 +35232,7 @@ var package_default = {
|
|
|
35225
35232
|
"test:watch": "vitest",
|
|
35226
35233
|
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
35227
35234
|
"test:docs": "playwright test --config tests/docs/playwright.config.ts",
|
|
35235
|
+
"test:e2e": "playwright test --config tests/e2e/playwright.config.ts",
|
|
35228
35236
|
eval: "tsx tests/evals/lib/runner.ts",
|
|
35229
35237
|
"eval:fixture-refresh": "tsx tests/evals/scripts/fetch-fixture.ts",
|
|
35230
35238
|
prepare: "npm run build",
|
|
@@ -35250,7 +35258,7 @@ var package_default = {
|
|
|
35250
35258
|
},
|
|
35251
35259
|
dependencies: {
|
|
35252
35260
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
35253
|
-
axios: "^1.
|
|
35261
|
+
axios: "^1.16.0",
|
|
35254
35262
|
"form-data": "^4.0.1"
|
|
35255
35263
|
},
|
|
35256
35264
|
devDependencies: {
|
|
@@ -35259,12 +35267,12 @@ var package_default = {
|
|
|
35259
35267
|
"@shikijs/engine-javascript": "^4.0.2",
|
|
35260
35268
|
"@shikijs/langs": "^4.0.2",
|
|
35261
35269
|
"@types/node": "^22.0.0",
|
|
35262
|
-
esbuild: "^0.
|
|
35270
|
+
esbuild: "^0.28.1",
|
|
35263
35271
|
sharp: "^0.33.5",
|
|
35264
35272
|
shiki: "^4.0.2",
|
|
35265
35273
|
tsx: "^4.21.0",
|
|
35266
35274
|
typescript: "^5.7.0",
|
|
35267
|
-
vitest: "^3.2.
|
|
35275
|
+
vitest: "^3.2.6"
|
|
35268
35276
|
},
|
|
35269
35277
|
engines: {
|
|
35270
35278
|
node: ">=20.0.0"
|
|
@@ -35278,6 +35286,9 @@ var package_default = {
|
|
|
35278
35286
|
],
|
|
35279
35287
|
publishConfig: {
|
|
35280
35288
|
access: "public"
|
|
35289
|
+
},
|
|
35290
|
+
overrides: {
|
|
35291
|
+
esbuild: "$esbuild"
|
|
35281
35292
|
}
|
|
35282
35293
|
};
|
|
35283
35294
|
|
|
@@ -39920,6 +39931,11 @@ function extractHints(data) {
|
|
|
39920
39931
|
if (typeof d2.block_name === "string") hints.block_name = d2.block_name;
|
|
39921
39932
|
if (typeof d2.suggested_replacement === "string") hints.suggested_replacement = d2.suggested_replacement;
|
|
39922
39933
|
if (typeof d2.status === "number") hints.status = d2.status;
|
|
39934
|
+
if (typeof d2.flat_index === "number") hints.flat_index = d2.flat_index;
|
|
39935
|
+
if (typeof d2.expected_revision === "number") hints.expected_revision = d2.expected_revision;
|
|
39936
|
+
if (typeof d2.current_revision === "number") hints.current_revision = d2.current_revision;
|
|
39937
|
+
if (typeof d2.max_depth === "number") hints.max_depth = d2.max_depth;
|
|
39938
|
+
if (typeof d2.actual_depth === "number") hints.actual_depth = d2.actual_depth;
|
|
39923
39939
|
return hints;
|
|
39924
39940
|
}
|
|
39925
39941
|
function translateWpError(code, data) {
|
|
@@ -39938,23 +39954,30 @@ function translateWpError(code, data) {
|
|
|
39938
39954
|
case "rest_authentication_required":
|
|
39939
39955
|
return "Authentication failed. Confirm WORDPRESS_USER and WORDPRESS_APP_PASSWORD are set to a valid Application Password (not a regular login password).";
|
|
39940
39956
|
// ── Post lookup ────────────────────────────────────────────────
|
|
39957
|
+
// `post_not_found` is the code the plugin actually emits;
|
|
39958
|
+
// `rest_post_invalid_id` is WordPress core's equivalent, kept as an
|
|
39959
|
+
// alias in case a core route ever surfaces it.
|
|
39941
39960
|
case "rest_post_invalid_id":
|
|
39942
|
-
case "
|
|
39961
|
+
case "post_not_found": {
|
|
39943
39962
|
const target = hints.post_id !== void 0 ? `Post ${hints.post_id}` : "Post";
|
|
39944
39963
|
return `${target} not found. List pages with \`list_posts\` to find the right ID.`;
|
|
39945
39964
|
}
|
|
39946
39965
|
case "not_found":
|
|
39947
39966
|
return hints.post_id ? `Post ${hints.post_id} not found. It may have been deleted, or the ID is wrong.` : "Resource not found. It may have been deleted, or the ID is wrong.";
|
|
39948
39967
|
// ── Block ref / path resolution ────────────────────────────────
|
|
39949
|
-
case "gk_block_api_invalid_ref":
|
|
39950
39968
|
case "invalid_ref":
|
|
39951
|
-
return
|
|
39952
|
-
case "
|
|
39969
|
+
return "Ref must be a non-empty string. Use the `ref` value returned by `get_page_blocks` \u2014 not a made-up ID.";
|
|
39970
|
+
case "ref_stale": {
|
|
39971
|
+
const where = hints.post_id !== void 0 ? ` in post ${hints.post_id}` : "";
|
|
39972
|
+
return `Block ref \`${hints.ref ?? "?"}\`${where} no longer resolves to a block. It may have been deleted, or the ref is from an older snapshot \u2014 call \`get_page_blocks\` again to get current refs.`;
|
|
39973
|
+
}
|
|
39953
39974
|
case "invalid_path":
|
|
39954
|
-
return `Block path ${formatPath(hints.path)} doesn't address an existing block. Re-fetch the post with \`get_page_blocks\` to get current paths \u2014 paths shift when blocks are added or removed.`;
|
|
39955
|
-
case "
|
|
39956
|
-
|
|
39957
|
-
|
|
39975
|
+
return `Block path ${formatPath(hints.path)} doesn't address an existing block (or isn't a valid array of non-negative integers). Re-fetch the post with \`get_page_blocks\` to get current paths \u2014 paths shift when blocks are added or removed.`;
|
|
39976
|
+
case "invalid_index": {
|
|
39977
|
+
const idx = typeof hints.flat_index === "number" ? ` ${hints.flat_index}` : "";
|
|
39978
|
+
return `Block index${idx} out of range. Re-fetch the post with \`get_page_blocks\` to get current indices \u2014 they shift when blocks are added or removed.`;
|
|
39979
|
+
}
|
|
39980
|
+
// ── Block tier / preference / storage enforcement ───────────────
|
|
39958
39981
|
case "legacy_block":
|
|
39959
39982
|
return blockName ? `${blockName} is in a namespace this site has configured as legacy. Use ${hints.suggested_replacement ?? "a core block instead"}.` : "Legacy block rejected. Use a core block (or a higher-tier alternative) instead.";
|
|
39960
39983
|
case "inner_html_required": {
|
|
@@ -39963,11 +39986,28 @@ function translateWpError(code, data) {
|
|
|
39963
39986
|
}
|
|
39964
39987
|
case "static_markup_stale_risk":
|
|
39965
39988
|
return "Updating attributes on a static block without new innerHTML may leave its rendered markup stale. Pass `innerHTML` alongside `attributes`, or use a dynamic block.";
|
|
39989
|
+
case "dual_storage_requires_both":
|
|
39990
|
+
return blockName ? `${blockName} is dual-storage: \`attributes\` and \`innerHTML\` carry the same data and must be sent together \u2014 sending only one silently desyncs the other. Pass both fields in the same call.` : "This block is dual-storage: `attributes` and `innerHTML` carry the same data and must be sent together \u2014 sending only one silently desyncs the other. Pass both fields in the same call.";
|
|
39991
|
+
case "block_depth_exceeded": {
|
|
39992
|
+
const depth = typeof hints.max_depth === "number" && typeof hints.actual_depth === "number" ? ` (max ${hints.max_depth}, got ${hints.actual_depth})` : "";
|
|
39993
|
+
return `Block tree exceeds the maximum nesting depth${depth}. Flatten the structure \u2014 split deeply nested groups into separate top-level blocks.`;
|
|
39994
|
+
}
|
|
39995
|
+
// ── Concurrency / staleness ──────────────────────────────────────
|
|
39996
|
+
case "edit_conflict":
|
|
39997
|
+
return "The post content changed since it was read (a concurrent write raced this one). Re-fetch the page with `get_page_blocks` and retry your edit against the current content.";
|
|
39998
|
+
case "stale_revision": {
|
|
39999
|
+
const rev = typeof hints.current_revision === "number" ? ` (current revision: ${hints.current_revision})` : "";
|
|
40000
|
+
return `The post has changed since you fetched it${rev}. Re-fetch with \`get_page_blocks\` and retry.`;
|
|
40001
|
+
}
|
|
39966
40002
|
// ── Rate limiting ──────────────────────────────────────────────
|
|
39967
40003
|
case "rate_limit_exceeded": {
|
|
39968
40004
|
const where = hints.post_id !== void 0 ? `on post ${hints.post_id} ` : "";
|
|
39969
40005
|
return `Too many writes ${where}in the last minute. Wait ~60s before retrying, or batch your edits into a single \`edit_block_tree\` call.`;
|
|
39970
40006
|
}
|
|
40007
|
+
case "rate_limit_locked": {
|
|
40008
|
+
const where = hints.post_id !== void 0 ? ` on post ${hints.post_id}` : "";
|
|
40009
|
+
return `Another write${where} is in progress. Retry in a moment; the lock clears within a second. To avoid contention, batch edits into a single \`edit_block_tree\` call.`;
|
|
40010
|
+
}
|
|
39971
40011
|
// ── v1.2 post lifecycle ────────────────────────────────────────
|
|
39972
40012
|
case "mixed_trash_payload":
|
|
39973
40013
|
return '`status: "trash"` cannot be combined with other fields. Trash the post in one call, then update other fields after.';
|
|
@@ -39975,6 +40015,8 @@ function translateWpError(code, data) {
|
|
|
39975
40015
|
return "Post type not allowed by this site's gk_block_api_post_types_allowlist option. Ask the site admin to add it, or pick a supported type.";
|
|
39976
40016
|
case "invalid_status":
|
|
39977
40017
|
return 'Post status not allowed. Valid values: draft, pending, publish, future, private. To trash, call update_post with status:"trash" (on its own, not combined with other fields).';
|
|
40018
|
+
case "trash_disabled":
|
|
40019
|
+
return "Moving posts to trash is turned off for this site. A site administrator can enable it under Block MCP \u2192 Settings, or use update_post with a different status.";
|
|
39978
40020
|
// ── Media uploads ──────────────────────────────────────────────
|
|
39979
40021
|
case "invalid_url":
|
|
39980
40022
|
return "URL rejected by SSRF guard. Hostnames pointing at private/loopback/cloud-metadata IPs are blocked. Use a publicly reachable URL.";
|
|
@@ -39989,6 +40031,29 @@ function formatPath(path2) {
|
|
|
39989
40031
|
return `[${path2.join(", ")}]`;
|
|
39990
40032
|
}
|
|
39991
40033
|
|
|
40034
|
+
// src/rest-url.ts
|
|
40035
|
+
function restRouteUrl(siteUrl, routeSuffix = "") {
|
|
40036
|
+
const trimmed = siteUrl.replace(/\/+$/, "");
|
|
40037
|
+
return `${trimmed}/?rest_route=/gk-block-api/v1${routeSuffix}`;
|
|
40038
|
+
}
|
|
40039
|
+
|
|
40040
|
+
// src/coerce.ts
|
|
40041
|
+
function coercePostId(value, label) {
|
|
40042
|
+
if (value === void 0 || value === null) {
|
|
40043
|
+
return void 0;
|
|
40044
|
+
}
|
|
40045
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value > 0) {
|
|
40046
|
+
return value;
|
|
40047
|
+
}
|
|
40048
|
+
if (typeof value === "string" && /^[0-9]+$/.test(value)) {
|
|
40049
|
+
const parsed = parseInt(value, 10);
|
|
40050
|
+
if (parsed > 0 && Number.isSafeInteger(parsed)) {
|
|
40051
|
+
return parsed;
|
|
40052
|
+
}
|
|
40053
|
+
}
|
|
40054
|
+
throw new Error(`${label}: post_id must be a positive integer`);
|
|
40055
|
+
}
|
|
40056
|
+
|
|
39992
40057
|
// src/client.ts
|
|
39993
40058
|
function mimeForFilename(filename) {
|
|
39994
40059
|
const ext = filename.toLowerCase().split(".").pop() ?? "";
|
|
@@ -40053,8 +40118,7 @@ var WordPressBlockClient = class {
|
|
|
40053
40118
|
const credentials = Buffer.from(
|
|
40054
40119
|
`${auth.username}:${auth.application_password}`
|
|
40055
40120
|
).toString("base64");
|
|
40056
|
-
const
|
|
40057
|
-
const baseURL = `${trimmed}/wp-json/gk-block-api/v1`;
|
|
40121
|
+
const baseURL = restRouteUrl(wordpress_url);
|
|
40058
40122
|
this.client = axios_default.create({
|
|
40059
40123
|
baseURL,
|
|
40060
40124
|
headers: {
|
|
@@ -40252,9 +40316,11 @@ var WordPressBlockClient = class {
|
|
|
40252
40316
|
* @returns Array of parsed blocks
|
|
40253
40317
|
*/
|
|
40254
40318
|
async getPageBlocks(postId, params) {
|
|
40255
|
-
|
|
40319
|
+
const coercedPostId = coercePostId(postId, "get_page_blocks");
|
|
40320
|
+
if (coercedPostId === void 0) {
|
|
40256
40321
|
throw new Error("Post ID is required");
|
|
40257
40322
|
}
|
|
40323
|
+
postId = coercedPostId;
|
|
40258
40324
|
const queryParams = {};
|
|
40259
40325
|
if (params?.fields) queryParams.fields = params.fields;
|
|
40260
40326
|
if (params?.render) queryParams.render = "true";
|
|
@@ -40321,7 +40387,9 @@ var WordPressBlockClient = class {
|
|
|
40321
40387
|
* @returns Updated block details with revision ID
|
|
40322
40388
|
*/
|
|
40323
40389
|
async updateBlock(postId, index, data) {
|
|
40324
|
-
|
|
40390
|
+
const coercedPostId = coercePostId(postId, "update_block");
|
|
40391
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40392
|
+
postId = coercedPostId;
|
|
40325
40393
|
if (index < 0) throw new Error("Block index must be non-negative");
|
|
40326
40394
|
if (!data.attributes && !data.innerHTML) {
|
|
40327
40395
|
throw new Error("At least one of attributes or innerHTML must be provided");
|
|
@@ -40342,7 +40410,9 @@ var WordPressBlockClient = class {
|
|
|
40342
40410
|
* @returns 404 ref_stale if the ref no longer matches any block.
|
|
40343
40411
|
*/
|
|
40344
40412
|
async updateBlockByRef(postId, ref, data) {
|
|
40345
|
-
|
|
40413
|
+
const coercedPostId = coercePostId(postId, "update_block");
|
|
40414
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40415
|
+
postId = coercedPostId;
|
|
40346
40416
|
if (!ref || typeof ref !== "string") throw new Error("Ref is required");
|
|
40347
40417
|
if (!data.attributes && !data.innerHTML) {
|
|
40348
40418
|
throw new Error("At least one of attributes or innerHTML must be provided");
|
|
@@ -40370,7 +40440,9 @@ var WordPressBlockClient = class {
|
|
|
40370
40440
|
* @returns Per-item results plus the single revision ID.
|
|
40371
40441
|
*/
|
|
40372
40442
|
async updateBlocksBatch(postId, updates, options = {}) {
|
|
40373
|
-
|
|
40443
|
+
const coercedPostId = coercePostId(postId, "update_blocks");
|
|
40444
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40445
|
+
postId = coercedPostId;
|
|
40374
40446
|
if (!Array.isArray(updates) || updates.length === 0) {
|
|
40375
40447
|
throw new Error("updates must be a non-empty array");
|
|
40376
40448
|
}
|
|
@@ -40396,7 +40468,9 @@ var WordPressBlockClient = class {
|
|
|
40396
40468
|
* @returns { success, saved } where `saved` mirrors update_block's saved.
|
|
40397
40469
|
*/
|
|
40398
40470
|
async getBlock(postId, target) {
|
|
40399
|
-
|
|
40471
|
+
const coercedPostId = coercePostId(postId, "get_block");
|
|
40472
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40473
|
+
postId = coercedPostId;
|
|
40400
40474
|
const hasRef = typeof target.ref === "string" && target.ref !== "";
|
|
40401
40475
|
const hasIdx = typeof target.flatIndex === "number";
|
|
40402
40476
|
if (hasRef === hasIdx) {
|
|
@@ -40416,7 +40490,9 @@ var WordPressBlockClient = class {
|
|
|
40416
40490
|
* @returns Inserted blocks with new indices, warnings, and revision ID
|
|
40417
40491
|
*/
|
|
40418
40492
|
async insertBlocks(postId, data) {
|
|
40419
|
-
|
|
40493
|
+
const coercedPostId = coercePostId(postId, "insert_blocks");
|
|
40494
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40495
|
+
postId = coercedPostId;
|
|
40420
40496
|
if (!data.blocks || data.blocks.length === 0) {
|
|
40421
40497
|
throw new Error("At least one block is required");
|
|
40422
40498
|
}
|
|
@@ -40435,7 +40511,9 @@ var WordPressBlockClient = class {
|
|
|
40435
40511
|
* @returns Deletion confirmation with revision ID
|
|
40436
40512
|
*/
|
|
40437
40513
|
async deleteBlock(postId, index, count) {
|
|
40438
|
-
|
|
40514
|
+
const coercedPostId = coercePostId(postId, "delete_block");
|
|
40515
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40516
|
+
postId = coercedPostId;
|
|
40439
40517
|
if (index < 0) throw new Error("Block index must be non-negative");
|
|
40440
40518
|
const params = {};
|
|
40441
40519
|
if (count && count > 1) params.count = String(count);
|
|
@@ -40453,7 +40531,9 @@ var WordPressBlockClient = class {
|
|
|
40453
40531
|
* @param count - Consecutive blocks to remove (default 1)
|
|
40454
40532
|
*/
|
|
40455
40533
|
async deleteBlockByRef(postId, ref, count) {
|
|
40456
|
-
|
|
40534
|
+
const coercedPostId = coercePostId(postId, "delete_block");
|
|
40535
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40536
|
+
postId = coercedPostId;
|
|
40457
40537
|
if (!ref || typeof ref !== "string") throw new Error("Ref is required");
|
|
40458
40538
|
const params = {};
|
|
40459
40539
|
if (count && count > 1) params.count = String(count);
|
|
@@ -40473,7 +40553,9 @@ var WordPressBlockClient = class {
|
|
|
40473
40553
|
* @returns Result with `removed`, `inserted[]`, warnings, revision IDs
|
|
40474
40554
|
*/
|
|
40475
40555
|
async replaceBlocksRange(postId, data) {
|
|
40476
|
-
|
|
40556
|
+
const coercedPostId = coercePostId(postId, "replace_block_range");
|
|
40557
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40558
|
+
postId = coercedPostId;
|
|
40477
40559
|
if (typeof data.start !== "number" || data.start < 0) {
|
|
40478
40560
|
throw new Error("start must be a non-negative integer");
|
|
40479
40561
|
}
|
|
@@ -40500,7 +40582,9 @@ var WordPressBlockClient = class {
|
|
|
40500
40582
|
* @returns Written blocks with revision ID
|
|
40501
40583
|
*/
|
|
40502
40584
|
async replaceAllBlocks(postId, blocks) {
|
|
40503
|
-
|
|
40585
|
+
const coercedPostId = coercePostId(postId, "rewrite_post_blocks");
|
|
40586
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40587
|
+
postId = coercedPostId;
|
|
40504
40588
|
if (!blocks || blocks.length === 0) {
|
|
40505
40589
|
throw new Error("At least one block is required for a full rewrite");
|
|
40506
40590
|
}
|
|
@@ -40521,9 +40605,11 @@ var WordPressBlockClient = class {
|
|
|
40521
40605
|
* @returns Mutation result with revision IDs and optional warnings
|
|
40522
40606
|
*/
|
|
40523
40607
|
async mutateBlockTree(postId, data) {
|
|
40524
|
-
|
|
40608
|
+
const coercedPostId = coercePostId(postId, "edit_block_tree");
|
|
40609
|
+
if (coercedPostId === void 0) {
|
|
40525
40610
|
throw new Error("Post ID is required");
|
|
40526
40611
|
}
|
|
40612
|
+
postId = coercedPostId;
|
|
40527
40613
|
const response = await this.client.post(
|
|
40528
40614
|
`/posts/${postId}/mutate`,
|
|
40529
40615
|
data
|
|
@@ -40541,9 +40627,11 @@ var WordPressBlockClient = class {
|
|
|
40541
40627
|
* @returns Revert result with revision IDs
|
|
40542
40628
|
*/
|
|
40543
40629
|
async revertToRevision(postId, revisionId) {
|
|
40544
|
-
|
|
40630
|
+
const coercedPostId = coercePostId(postId, "revert_to_revision");
|
|
40631
|
+
if (coercedPostId === void 0) {
|
|
40545
40632
|
throw new Error("Post ID is required");
|
|
40546
40633
|
}
|
|
40634
|
+
postId = coercedPostId;
|
|
40547
40635
|
const response = await this.client.post(`/posts/${postId}/revert`, { revision_id: revisionId });
|
|
40548
40636
|
return response.data;
|
|
40549
40637
|
}
|
|
@@ -40558,7 +40646,9 @@ var WordPressBlockClient = class {
|
|
|
40558
40646
|
* @returns Inserted pattern details with revision ID
|
|
40559
40647
|
*/
|
|
40560
40648
|
async insertPattern(postId, data) {
|
|
40561
|
-
|
|
40649
|
+
const coercedPostId = coercePostId(postId, "insert_pattern");
|
|
40650
|
+
if (coercedPostId === void 0) throw new Error("Post ID is required");
|
|
40651
|
+
postId = coercedPostId;
|
|
40562
40652
|
if (data.pattern_id === void 0 || data.pattern_id === null) throw new Error("Pattern ID is required");
|
|
40563
40653
|
const response = await this.client.post(
|
|
40564
40654
|
`/posts/${postId}/insert-pattern`,
|
|
@@ -40593,9 +40683,11 @@ var WordPressBlockClient = class {
|
|
|
40593
40683
|
* Use `status: trash` to trash; any non-trash status untrashes a trashed post.
|
|
40594
40684
|
*/
|
|
40595
40685
|
async updatePost(postId, data) {
|
|
40596
|
-
|
|
40686
|
+
const coercedPostId = coercePostId(postId, "update_post");
|
|
40687
|
+
if (coercedPostId === void 0) {
|
|
40597
40688
|
throw new Error("update_post: post_id is required");
|
|
40598
40689
|
}
|
|
40690
|
+
postId = coercedPostId;
|
|
40599
40691
|
const response = await this.client.patch(`/posts/${postId}`, data);
|
|
40600
40692
|
return response.data;
|
|
40601
40693
|
}
|
|
@@ -40655,17 +40747,21 @@ var WordPressBlockClient = class {
|
|
|
40655
40747
|
// ──────────────────────────────────────────────────────────
|
|
40656
40748
|
/** Read all Yoast SEO metadata for a post. */
|
|
40657
40749
|
async getYoastSEO(postId) {
|
|
40658
|
-
|
|
40750
|
+
const coercedPostId = coercePostId(postId, "yoast_get_seo");
|
|
40751
|
+
if (coercedPostId === void 0) {
|
|
40659
40752
|
throw new Error("yoast_get_seo: post_id is required");
|
|
40660
40753
|
}
|
|
40754
|
+
postId = coercedPostId;
|
|
40661
40755
|
const response = await this.client.get(`/yoast/${postId}`);
|
|
40662
40756
|
return response.data;
|
|
40663
40757
|
}
|
|
40664
40758
|
/** Partial update of Yoast SEO fields on a single post. */
|
|
40665
40759
|
async updateYoastSEO(postId, fields) {
|
|
40666
|
-
|
|
40760
|
+
const coercedPostId = coercePostId(postId, "yoast_update_seo");
|
|
40761
|
+
if (coercedPostId === void 0) {
|
|
40667
40762
|
throw new Error("yoast_update_seo: post_id is required");
|
|
40668
40763
|
}
|
|
40764
|
+
postId = coercedPostId;
|
|
40669
40765
|
const response = await this.client.patch(`/yoast/${postId}`, fields);
|
|
40670
40766
|
return response.data;
|
|
40671
40767
|
}
|
|
@@ -40679,6 +40775,51 @@ var WordPressBlockClient = class {
|
|
|
40679
40775
|
}
|
|
40680
40776
|
};
|
|
40681
40777
|
|
|
40778
|
+
// src/config.ts
|
|
40779
|
+
function readEnv(env, primary, legacy) {
|
|
40780
|
+
const fromPrimary = env[primary];
|
|
40781
|
+
if (fromPrimary && fromPrimary.trim() !== "") {
|
|
40782
|
+
return fromPrimary;
|
|
40783
|
+
}
|
|
40784
|
+
const fromLegacy = env[legacy];
|
|
40785
|
+
if (fromLegacy && fromLegacy.trim() !== "") {
|
|
40786
|
+
console.error(`[block-mcp] DEPRECATED: ${legacy} is deprecated; rename to ${primary} in your MCP client config.`);
|
|
40787
|
+
return fromLegacy;
|
|
40788
|
+
}
|
|
40789
|
+
return void 0;
|
|
40790
|
+
}
|
|
40791
|
+
function resolveWordPressConfig(env) {
|
|
40792
|
+
const url3 = readEnv(env, "WORDPRESS_URL", "GK_SITE_URL");
|
|
40793
|
+
const user = readEnv(env, "WORDPRESS_USER", "GK_BLOCK_API_USER");
|
|
40794
|
+
const password = readEnv(env, "WORDPRESS_APP_PASSWORD", "GK_BLOCK_API_APP_PASSWORD");
|
|
40795
|
+
const missing = [];
|
|
40796
|
+
if (!url3) {
|
|
40797
|
+
missing.push("WORDPRESS_URL");
|
|
40798
|
+
}
|
|
40799
|
+
if (!user) {
|
|
40800
|
+
missing.push("WORDPRESS_USER");
|
|
40801
|
+
}
|
|
40802
|
+
if (!password) {
|
|
40803
|
+
missing.push("WORDPRESS_APP_PASSWORD");
|
|
40804
|
+
}
|
|
40805
|
+
if (missing.length > 0) {
|
|
40806
|
+
const message = `Block MCP is not configured: ${missing.join(", ")} ${missing.length === 1 ? "is" : "are"} missing. Set them in the "env" block of the block-mcp server entry in your MCP client config. Your site's Settings \u2192 Block MCP \u2192 Connect generates a ready-made config for you.`;
|
|
40807
|
+
return { ok: false, missing, message };
|
|
40808
|
+
}
|
|
40809
|
+
return { ok: true, config: { url: url3, user, password } };
|
|
40810
|
+
}
|
|
40811
|
+
function buildNotConfiguredResult(message) {
|
|
40812
|
+
return {
|
|
40813
|
+
content: [
|
|
40814
|
+
{
|
|
40815
|
+
type: "text",
|
|
40816
|
+
text: JSON.stringify({ error: true, code: "not_configured", message }, null, 2)
|
|
40817
|
+
}
|
|
40818
|
+
],
|
|
40819
|
+
isError: true
|
|
40820
|
+
};
|
|
40821
|
+
}
|
|
40822
|
+
|
|
40682
40823
|
// src/instructions.ts
|
|
40683
40824
|
var BASELINE = `Block-level WordPress CRUD. URL \u2192 post_id is resolved server-side \u2014 pass URLs directly to get_page_blocks / resolve_url; never shell out to curl or wp-json.
|
|
40684
40825
|
|
|
@@ -40717,8 +40858,7 @@ async function fetchAddendum(wordpressUrl) {
|
|
|
40717
40858
|
if (process.env[OFF_ENV_VAR] === "1") {
|
|
40718
40859
|
return "";
|
|
40719
40860
|
}
|
|
40720
|
-
const
|
|
40721
|
-
const url3 = `${base}/wp-json/gk-block-api/v1/instructions`;
|
|
40861
|
+
const url3 = restRouteUrl(wordpressUrl, "/instructions");
|
|
40722
40862
|
try {
|
|
40723
40863
|
const response = await axios_default.get(url3, {
|
|
40724
40864
|
timeout: FETCH_TIMEOUT_MS,
|
|
@@ -40819,7 +40959,9 @@ function enrichPatternList(patterns) {
|
|
|
40819
40959
|
const sorted = [...patterns].sort(
|
|
40820
40960
|
(a2, b3) => b3.preference.score - a2.preference.score
|
|
40821
40961
|
);
|
|
40822
|
-
const recommended = sorted.filter(
|
|
40962
|
+
const recommended = sorted.filter(
|
|
40963
|
+
(p2) => p2.preference.tier === "preferred" || p2.preference.tier === "acceptable"
|
|
40964
|
+
);
|
|
40823
40965
|
const avoid = sorted.filter((p2) => p2.preference.tier === "avoid" || p2.preference.tier === "legacy");
|
|
40824
40966
|
const lines = [];
|
|
40825
40967
|
if (recommended.length > 0) {
|
|
@@ -40867,51 +41009,39 @@ function enrichBlockTypes(types) {
|
|
|
40867
41009
|
}
|
|
40868
41010
|
}
|
|
40869
41011
|
const lines = [];
|
|
40870
|
-
|
|
40871
|
-
|
|
40872
|
-
|
|
40873
|
-
|
|
40874
|
-
lines.push(`PREFERRED (${ns}/): ${names}`);
|
|
40875
|
-
}
|
|
40876
|
-
}
|
|
40877
|
-
if (acceptable.length > 0) {
|
|
40878
|
-
const grouped = groupByNamespace(acceptable);
|
|
40879
|
-
for (const [ns, blocks] of Object.entries(grouped)) {
|
|
40880
|
-
const names = blocks.map((t) => getShortName(t.name)).join(", ");
|
|
40881
|
-
lines.push(`ACCEPTABLE (${ns}/): ${names}`);
|
|
40882
|
-
}
|
|
40883
|
-
}
|
|
40884
|
-
if (avoid.length > 0) {
|
|
40885
|
-
const grouped = groupByNamespace(avoid);
|
|
40886
|
-
for (const [ns, blocks] of Object.entries(grouped)) {
|
|
40887
|
-
const mappings = blocks.map((t) => {
|
|
40888
|
-
const replacement = t.preference.replacement;
|
|
40889
|
-
const shortName = getShortName(t.name);
|
|
40890
|
-
return replacement ? `${shortName} -> use ${replacement}` : shortName;
|
|
40891
|
-
});
|
|
40892
|
-
lines.push(`AVOID (${ns}/): ${mappings.join(", ")}`);
|
|
40893
|
-
}
|
|
40894
|
-
}
|
|
40895
|
-
if (legacy.length > 0) {
|
|
40896
|
-
const grouped = groupByNamespace(legacy);
|
|
40897
|
-
for (const [ns, blocks] of Object.entries(grouped)) {
|
|
40898
|
-
const mappings = blocks.map((t) => {
|
|
40899
|
-
const replacement = t.preference.replacement;
|
|
40900
|
-
const shortName = getShortName(t.name);
|
|
40901
|
-
return replacement ? `${shortName} -> use ${replacement}` : shortName;
|
|
40902
|
-
});
|
|
40903
|
-
lines.push(`LEGACY \u2014 DO NOT USE (${ns}/): ${mappings.join(", ")}`);
|
|
40904
|
-
}
|
|
40905
|
-
}
|
|
41012
|
+
pushTierLines(lines, preferred, "PREFERRED", false);
|
|
41013
|
+
pushTierLines(lines, acceptable, "ACCEPTABLE", false);
|
|
41014
|
+
pushTierLines(lines, avoid, "AVOID", true);
|
|
41015
|
+
pushTierLines(lines, legacy, "LEGACY \u2014 DO NOT USE", true);
|
|
40906
41016
|
const guidance = lines.join("\n");
|
|
40907
41017
|
return { block_types: types, guidance };
|
|
40908
41018
|
}
|
|
41019
|
+
function pushTierLines(lines, bucket, label, withReplacement) {
|
|
41020
|
+
if (bucket.length === 0) return;
|
|
41021
|
+
const grouped = groupByNamespace(bucket);
|
|
41022
|
+
for (const [ns, blocks] of Object.entries(grouped)) {
|
|
41023
|
+
const names = blocks.map((t) => {
|
|
41024
|
+
const shortName = getShortName(t.name);
|
|
41025
|
+
if (!withReplacement) return shortName;
|
|
41026
|
+
const replacement = t.preference.replacement;
|
|
41027
|
+
return replacement ? `${shortName} -> use ${replacement}` : shortName;
|
|
41028
|
+
});
|
|
41029
|
+
lines.push(`${label} (${ns}/): ${names.join(", ")}`);
|
|
41030
|
+
}
|
|
41031
|
+
}
|
|
40909
41032
|
function formatPreferenceWarning(warning) {
|
|
40910
41033
|
if (warning.suggested_replacement) {
|
|
40911
41034
|
return `WARNING: ${warning.block} is non-preferred. Use ${warning.suggested_replacement} instead.`;
|
|
40912
41035
|
}
|
|
40913
41036
|
return `WARNING: ${warning.message}`;
|
|
40914
41037
|
}
|
|
41038
|
+
function withFormattedWarnings(result, formatWarning) {
|
|
41039
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
41040
|
+
const warnings = result.warnings;
|
|
41041
|
+
return { ...result, formatted_warnings: warnings.map(formatWarning) };
|
|
41042
|
+
}
|
|
41043
|
+
return result;
|
|
41044
|
+
}
|
|
40915
41045
|
function groupByNamespace(types) {
|
|
40916
41046
|
const groups = {};
|
|
40917
41047
|
for (const t of types) {
|
|
@@ -41075,8 +41205,6 @@ async function handleDiscoveryTool(toolName, args, client) {
|
|
|
41075
41205
|
q: args.search,
|
|
41076
41206
|
synced: args.synced,
|
|
41077
41207
|
min_score: args.min_score,
|
|
41078
|
-
// Fetch enough to honor offset+limit. Server caps respond too.
|
|
41079
|
-
limit: offset + limit,
|
|
41080
41208
|
refresh: args.refresh
|
|
41081
41209
|
});
|
|
41082
41210
|
const enriched = enrichPatternList(response.patterns);
|
|
@@ -41120,14 +41248,7 @@ async function handleDiscoveryTool(toolName, args, client) {
|
|
|
41120
41248
|
if ((postId === void 0 || postId === null) && (typeof url3 !== "string" || url3.length === 0) && (typeof slug !== "string" || slug.length === 0)) {
|
|
41121
41249
|
throw new Error("get_post_info requires one of: post_id, url, or slug");
|
|
41122
41250
|
}
|
|
41123
|
-
|
|
41124
|
-
if (typeof postId === "number" && Number.isInteger(postId) && postId > 0) {
|
|
41125
|
-
normalizedPostId = postId;
|
|
41126
|
-
} else if (typeof postId === "string" && /^[0-9]+$/.test(postId)) {
|
|
41127
|
-
normalizedPostId = parseInt(postId, 10);
|
|
41128
|
-
} else if (postId !== void 0 && postId !== null) {
|
|
41129
|
-
throw new Error("get_post_info: post_id must be a positive integer");
|
|
41130
|
-
}
|
|
41251
|
+
const normalizedPostId = coercePostId(postId, "get_post_info");
|
|
41131
41252
|
return await client.getPostInfo({
|
|
41132
41253
|
post_id: normalizedPostId,
|
|
41133
41254
|
url: typeof url3 === "string" ? url3 : void 0,
|
|
@@ -41251,7 +41372,7 @@ var READ_TOOLS = [
|
|
|
41251
41372
|
async function handleReadTool(toolName, args, client) {
|
|
41252
41373
|
switch (toolName) {
|
|
41253
41374
|
case "get_page_blocks": {
|
|
41254
|
-
let postId = args.post_id;
|
|
41375
|
+
let postId = coercePostId(args.post_id, "get_page_blocks");
|
|
41255
41376
|
const url3 = args.url;
|
|
41256
41377
|
const fields = args.fields;
|
|
41257
41378
|
const render = args.render;
|
|
@@ -41263,10 +41384,10 @@ async function handleReadTool(toolName, args, client) {
|
|
|
41263
41384
|
const persistRefs = args.persist_refs;
|
|
41264
41385
|
const limit = args.limit;
|
|
41265
41386
|
const cursor = args.cursor;
|
|
41266
|
-
if (
|
|
41387
|
+
if (postId === void 0 && !url3) {
|
|
41267
41388
|
throw new Error("Either post_id or url is required");
|
|
41268
41389
|
}
|
|
41269
|
-
if (postId === void 0
|
|
41390
|
+
if (postId === void 0) {
|
|
41270
41391
|
const resolved = await client.resolveUrl(url3);
|
|
41271
41392
|
postId = resolved.post_id;
|
|
41272
41393
|
}
|
|
@@ -41300,10 +41421,10 @@ async function handleReadTool(toolName, args, client) {
|
|
|
41300
41421
|
};
|
|
41301
41422
|
}
|
|
41302
41423
|
case "get_block": {
|
|
41303
|
-
const postId = args.post_id;
|
|
41424
|
+
const postId = coercePostId(args.post_id, "get_block");
|
|
41304
41425
|
const ref = typeof args.ref === "string" && args.ref.length > 0 ? args.ref : void 0;
|
|
41305
|
-
const flatIndex = typeof args.flat_index === "number" && Number.
|
|
41306
|
-
if (postId === void 0
|
|
41426
|
+
const flatIndex = typeof args.flat_index === "number" && Number.isInteger(args.flat_index) && args.flat_index >= 0 ? args.flat_index : void 0;
|
|
41427
|
+
if (postId === void 0) {
|
|
41307
41428
|
throw new Error("post_id is required");
|
|
41308
41429
|
}
|
|
41309
41430
|
const hasRef = ref !== void 0;
|
|
@@ -52027,7 +52148,7 @@ async function shikiHighlight(code, language, themeName) {
|
|
|
52027
52148
|
const lang29 = langs.has(language) ? language : "plaintext";
|
|
52028
52149
|
let html5 = hl.codeToHtml(code, { lang: lang29, theme: "css-variables" }).replace(/var\(--shiki-foreground\)/g, "var(--shiki-color-text)").replace(/var\(--shiki-background\)/g, "var(--shiki-color-background)");
|
|
52029
52150
|
if (themeName && themeName !== "css-variables") {
|
|
52030
|
-
html5 = html5.replace(/(<pre[^>]*class="shiki) css-variables(")/, `$
|
|
52151
|
+
html5 = html5.replace(/(<pre[^>]*class="shiki) css-variables(")/, (_m, p1, p2) => `${p1} ${themeName}${p2}`);
|
|
52031
52152
|
}
|
|
52032
52153
|
return html5;
|
|
52033
52154
|
}
|
|
@@ -52089,7 +52210,7 @@ registerBlockEnricher("kevinbatdorf/code-block-pro", async (block) => {
|
|
|
52089
52210
|
if (incomingInnerHTML !== "") {
|
|
52090
52211
|
updatedInnerHTML = incomingInnerHTML.replace(
|
|
52091
52212
|
/<pre class="shiki[\s\S]*?<\/pre>/,
|
|
52092
|
-
codeHTML
|
|
52213
|
+
() => codeHTML
|
|
52093
52214
|
);
|
|
52094
52215
|
updatedInnerHTML = updatedInnerHTML.replace(
|
|
52095
52216
|
/(<textarea[^>]*>)([\s\S]*?)(<\/textarea>)/,
|
|
@@ -52164,7 +52285,9 @@ var WRITE_TOOLS = [
|
|
|
52164
52285
|
// idempotentHint is false: every call creates a new revision, and
|
|
52165
52286
|
// revision history is observable to other readers. Same-input/same-state
|
|
52166
52287
|
// is true at the block level but not at the post level.
|
|
52167
|
-
|
|
52288
|
+
// destructiveHint is true: attributes/innerHTML overwrite the block's
|
|
52289
|
+
// existing content rather than merging additively.
|
|
52290
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true, title: "Update one block" },
|
|
52168
52291
|
outputSchema: {
|
|
52169
52292
|
type: "object",
|
|
52170
52293
|
properties: {
|
|
@@ -52211,7 +52334,8 @@ var WRITE_TOOLS = [
|
|
|
52211
52334
|
{
|
|
52212
52335
|
name: "update_blocks",
|
|
52213
52336
|
description: "Update N independent blocks atomically in ONE revision. Each item targets one block by `ref` (recommended) or `flat_index`, with `attributes` and/or `innerHTML`. Validation is all-or-nothing: any stale ref / out-of-range index / dual-storage rejection / duplicate target aborts the batch with itemized errors \u2014 no partial writes hit disk. Max 50 items per call. Counts as ONE write against the per-post rate limit. Use this instead of looping update_block when fixing multiple blocks on the same post \u2014 keeps revision history clean. Pass `verbose: true` to include `saved.inner_html` + `saved.attributes` per result for per-item verification without a re-read.",
|
|
52214
|
-
|
|
52337
|
+
// destructiveHint is true: same overwrite semantics as update_block, applied per item.
|
|
52338
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true, title: "Batch-update blocks" },
|
|
52215
52339
|
outputSchema: {
|
|
52216
52340
|
type: "object",
|
|
52217
52341
|
properties: {
|
|
@@ -52405,13 +52529,13 @@ var WRITE_TOOLS = [
|
|
|
52405
52529
|
async function handleWriteTool(toolName, args, client) {
|
|
52406
52530
|
switch (toolName) {
|
|
52407
52531
|
case "update_block": {
|
|
52408
|
-
const postId = args.post_id;
|
|
52532
|
+
const postId = coercePostId(args.post_id, "update_block");
|
|
52409
52533
|
const flatIndex = args.flat_index;
|
|
52410
52534
|
const ref = args.ref;
|
|
52411
52535
|
const blockName = args.block_name;
|
|
52412
52536
|
let attributes = args.attributes;
|
|
52413
52537
|
let innerHTML = args.innerHTML;
|
|
52414
|
-
if (postId === void 0
|
|
52538
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52415
52539
|
const hasIndex = typeof flatIndex === "number" && Number.isFinite(flatIndex) && flatIndex >= 0;
|
|
52416
52540
|
const hasRef = typeof ref === "string" && ref.length > 0;
|
|
52417
52541
|
if (!hasIndex && !hasRef) {
|
|
@@ -52435,9 +52559,9 @@ async function handleWriteTool(toolName, args, client) {
|
|
|
52435
52559
|
return await client.updateBlock(postId, flatIndex, { attributes, innerHTML });
|
|
52436
52560
|
}
|
|
52437
52561
|
case "update_blocks": {
|
|
52438
|
-
const postId = args.post_id;
|
|
52562
|
+
const postId = coercePostId(args.post_id, "update_blocks");
|
|
52439
52563
|
const updates = args.updates;
|
|
52440
|
-
if (postId === void 0
|
|
52564
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52441
52565
|
if (!Array.isArray(updates) || updates.length === 0) {
|
|
52442
52566
|
throw new Error("updates must be a non-empty array");
|
|
52443
52567
|
}
|
|
@@ -52481,13 +52605,13 @@ async function handleWriteTool(toolName, args, client) {
|
|
|
52481
52605
|
return await client.updateBlocksBatch(postId, normalized);
|
|
52482
52606
|
}
|
|
52483
52607
|
case "insert_blocks": {
|
|
52484
|
-
const postId = args.post_id;
|
|
52608
|
+
const postId = coercePostId(args.post_id, "insert_blocks");
|
|
52485
52609
|
const after = args.after_top_level;
|
|
52486
52610
|
const before = args.before_top_level;
|
|
52487
52611
|
const afterRef = args.after_ref;
|
|
52488
52612
|
const beforeRef = args.before_ref;
|
|
52489
52613
|
const blocks = args.blocks;
|
|
52490
|
-
if (postId === void 0
|
|
52614
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52491
52615
|
if (!blocks || blocks.length === 0) throw new Error("At least one block is required in the blocks array");
|
|
52492
52616
|
const result = await client.insertBlocks(postId, {
|
|
52493
52617
|
after,
|
|
@@ -52496,17 +52620,14 @@ async function handleWriteTool(toolName, args, client) {
|
|
|
52496
52620
|
...beforeRef ? { before_ref: beforeRef } : {},
|
|
52497
52621
|
blocks: await enrichBlocks(blocks)
|
|
52498
52622
|
});
|
|
52499
|
-
|
|
52500
|
-
return { ...result, formatted_warnings: result.warnings.map(formatPreferenceWarning) };
|
|
52501
|
-
}
|
|
52502
|
-
return result;
|
|
52623
|
+
return withFormattedWarnings(result, formatPreferenceWarning);
|
|
52503
52624
|
}
|
|
52504
52625
|
case "delete_block": {
|
|
52505
|
-
const postId = args.post_id;
|
|
52626
|
+
const postId = coercePostId(args.post_id, "delete_block");
|
|
52506
52627
|
const topLevelCounter = args.top_level_counter;
|
|
52507
52628
|
const ref = args.ref;
|
|
52508
52629
|
const count = args.count;
|
|
52509
|
-
if (postId === void 0
|
|
52630
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52510
52631
|
const hasCounter = typeof topLevelCounter === "number" && Number.isFinite(topLevelCounter) && topLevelCounter >= 0;
|
|
52511
52632
|
const hasRef = typeof ref === "string" && ref.length > 0;
|
|
52512
52633
|
if (!hasCounter && !hasRef) {
|
|
@@ -52526,35 +52647,29 @@ async function handleWriteTool(toolName, args, client) {
|
|
|
52526
52647
|
return await client.deleteBlock(postId, topLevelCounter, count);
|
|
52527
52648
|
}
|
|
52528
52649
|
case "replace_block_range": {
|
|
52529
|
-
const postId = args.post_id;
|
|
52650
|
+
const postId = coercePostId(args.post_id, "replace_block_range");
|
|
52530
52651
|
const start = args.start;
|
|
52531
52652
|
const count = args.count;
|
|
52532
52653
|
const blocks = args.blocks;
|
|
52533
|
-
if (postId === void 0
|
|
52534
|
-
if (
|
|
52535
|
-
if (
|
|
52654
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52655
|
+
if (!Number.isSafeInteger(start) || start < 0) throw new Error("start must be a non-negative integer");
|
|
52656
|
+
if (!Number.isSafeInteger(count) || count < 0) throw new Error("count must be a non-negative integer");
|
|
52536
52657
|
if (!Array.isArray(blocks)) throw new Error("blocks must be an array (may be empty for a pure delete)");
|
|
52537
52658
|
const result = await client.replaceBlocksRange(postId, { start, count, blocks: await enrichBlocks(blocks) });
|
|
52538
|
-
|
|
52539
|
-
return { ...result, formatted_warnings: result.warnings.map(formatPreferenceWarning) };
|
|
52540
|
-
}
|
|
52541
|
-
return result;
|
|
52659
|
+
return withFormattedWarnings(result, formatPreferenceWarning);
|
|
52542
52660
|
}
|
|
52543
52661
|
case "rewrite_post_blocks": {
|
|
52544
|
-
const postId = args.post_id;
|
|
52662
|
+
const postId = coercePostId(args.post_id, "rewrite_post_blocks");
|
|
52545
52663
|
const blocks = args.blocks;
|
|
52546
|
-
if (postId === void 0
|
|
52664
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52547
52665
|
if (!blocks || blocks.length === 0) throw new Error("At least one block is required for a full page rewrite");
|
|
52548
52666
|
const result = await client.replaceAllBlocks(postId, await enrichBlocks(blocks));
|
|
52549
|
-
|
|
52550
|
-
return { ...result, formatted_warnings: result.warnings.map(formatPreferenceWarning) };
|
|
52551
|
-
}
|
|
52552
|
-
return result;
|
|
52667
|
+
return withFormattedWarnings(result, formatPreferenceWarning);
|
|
52553
52668
|
}
|
|
52554
52669
|
case "revert_to_revision": {
|
|
52555
|
-
const postId = args.post_id;
|
|
52670
|
+
const postId = coercePostId(args.post_id, "revert_to_revision");
|
|
52556
52671
|
const revisionId = args.revision_id;
|
|
52557
|
-
if (postId === void 0
|
|
52672
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52558
52673
|
if (revisionId === void 0 || revisionId === null) throw new Error("revision_id is required");
|
|
52559
52674
|
return await client.revertToRevision(postId, revisionId);
|
|
52560
52675
|
}
|
|
@@ -52600,12 +52715,12 @@ var PATTERN_TOOLS = [
|
|
|
52600
52715
|
async function handlePatternTool(toolName, args, client) {
|
|
52601
52716
|
switch (toolName) {
|
|
52602
52717
|
case "insert_pattern": {
|
|
52603
|
-
const postId = args.post_id;
|
|
52718
|
+
const postId = coercePostId(args.post_id, "insert_pattern");
|
|
52604
52719
|
const patternId = args.pattern_id;
|
|
52605
52720
|
const after = args.after_top_level;
|
|
52606
52721
|
const before = args.before_top_level;
|
|
52607
52722
|
const synced = args.synced;
|
|
52608
|
-
if (postId === void 0
|
|
52723
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52609
52724
|
if (patternId === void 0 || patternId === null) throw new Error("pattern_id is required");
|
|
52610
52725
|
const result = await client.insertPattern(postId, {
|
|
52611
52726
|
pattern_id: patternId,
|
|
@@ -52711,11 +52826,11 @@ async function handleMutateTool(toolName, args, client) {
|
|
|
52711
52826
|
if (toolName !== "edit_block_tree") {
|
|
52712
52827
|
throw new Error(`Unknown mutate tool: ${toolName}`);
|
|
52713
52828
|
}
|
|
52714
|
-
const postId = args.post_id;
|
|
52829
|
+
const postId = coercePostId(args.post_id, "edit_block_tree");
|
|
52715
52830
|
const op = args.op;
|
|
52716
52831
|
const path2 = args.path;
|
|
52717
52832
|
const ref = args.ref;
|
|
52718
|
-
if (postId === void 0
|
|
52833
|
+
if (postId === void 0) throw new Error("post_id is required");
|
|
52719
52834
|
if (!op || !OPS.includes(op)) {
|
|
52720
52835
|
throw new Error(`op must be one of: ${OPS.join(", ")}. Got: ${JSON.stringify(op)}`);
|
|
52721
52836
|
}
|
|
@@ -52763,10 +52878,16 @@ async function handleMutateTool(toolName, args, client) {
|
|
|
52763
52878
|
requestBody.block = block;
|
|
52764
52879
|
if (op === "insert-child" && args.position !== void 0) {
|
|
52765
52880
|
const position = args.position;
|
|
52766
|
-
if (typeof position === "number" && Number.isInteger(position)) {
|
|
52881
|
+
if (typeof position === "number" && Number.isInteger(position) && position >= -1) {
|
|
52767
52882
|
requestBody.position = position;
|
|
52768
52883
|
} else if (position === "start" || position === "end") {
|
|
52769
52884
|
requestBody.position = position;
|
|
52885
|
+
} else if (typeof position === "string" && /^-?\d+$/.test(position)) {
|
|
52886
|
+
const parsedPosition = parseInt(position, 10);
|
|
52887
|
+
if (parsedPosition < -1) {
|
|
52888
|
+
throw new Error('position must be an integer >= -1, "start", or "end"');
|
|
52889
|
+
}
|
|
52890
|
+
requestBody.position = parsedPosition;
|
|
52770
52891
|
} else {
|
|
52771
52892
|
throw new Error('position must be an integer, "start", or "end"');
|
|
52772
52893
|
}
|
|
@@ -52808,14 +52929,10 @@ async function handleMutateTool(toolName, args, client) {
|
|
|
52808
52929
|
}
|
|
52809
52930
|
}
|
|
52810
52931
|
const result = await client.mutateBlockTree(postId, requestBody);
|
|
52811
|
-
|
|
52812
|
-
|
|
52813
|
-
|
|
52814
|
-
|
|
52815
|
-
});
|
|
52816
|
-
return { ...result, formatted_warnings: formattedWarnings };
|
|
52817
|
-
}
|
|
52818
|
-
return result;
|
|
52932
|
+
return withFormattedWarnings(
|
|
52933
|
+
result,
|
|
52934
|
+
(warning) => isStaticBlockWarning(warning) ? formatStaticBlockWarning(warning) : formatPreferenceWarning(warning)
|
|
52935
|
+
);
|
|
52819
52936
|
}
|
|
52820
52937
|
|
|
52821
52938
|
// src/tools/posts.ts
|
|
@@ -52921,10 +53038,12 @@ async function handlePostTool(toolName, args, client) {
|
|
|
52921
53038
|
return client.createPost(create3);
|
|
52922
53039
|
}
|
|
52923
53040
|
case "update_post": {
|
|
52924
|
-
|
|
52925
|
-
|
|
53041
|
+
const postId = coercePostId(args.post_id, "update_post");
|
|
53042
|
+
if (postId === void 0) {
|
|
53043
|
+
throw new Error('update_post: "post_id" is required');
|
|
52926
53044
|
}
|
|
52927
|
-
const { post_id:
|
|
53045
|
+
const { post_id: _omit, ...rest } = args;
|
|
53046
|
+
void _omit;
|
|
52928
53047
|
if (Object.keys(rest).length === 0) {
|
|
52929
53048
|
throw new Error("update_post: provide at least one mutating field besides post_id");
|
|
52930
53049
|
}
|
|
@@ -52935,12 +53054,8 @@ async function handlePostTool(toolName, args, client) {
|
|
|
52935
53054
|
throw new Error(`Unknown post tool: ${toolName}`);
|
|
52936
53055
|
}
|
|
52937
53056
|
}
|
|
52938
|
-
function
|
|
52939
|
-
const out = {
|
|
52940
|
-
if (typeof input.post_type === "string") out.post_type = input.post_type;
|
|
52941
|
-
if (typeof input.status === "string") out.status = input.status;
|
|
52942
|
-
if (typeof input.content === "string") out.content = input.content;
|
|
52943
|
-
if (Array.isArray(input.blocks)) out.blocks = input.blocks;
|
|
53057
|
+
function narrowCommonPostFields(input) {
|
|
53058
|
+
const out = {};
|
|
52944
53059
|
if (typeof input.slug === "string") out.slug = input.slug;
|
|
52945
53060
|
if (typeof input.parent === "number") out.parent = input.parent;
|
|
52946
53061
|
if (typeof input.excerpt === "string") out.excerpt = input.excerpt;
|
|
@@ -52957,24 +53072,18 @@ function narrowCreatePost(input) {
|
|
|
52957
53072
|
if (typeof input.author === "number") out.author = input.author;
|
|
52958
53073
|
return out;
|
|
52959
53074
|
}
|
|
53075
|
+
function narrowCreatePost(input) {
|
|
53076
|
+
const out = { title: input.title, ...narrowCommonPostFields(input) };
|
|
53077
|
+
if (typeof input.post_type === "string") out.post_type = input.post_type;
|
|
53078
|
+
if (typeof input.status === "string") out.status = input.status;
|
|
53079
|
+
if (typeof input.content === "string") out.content = input.content;
|
|
53080
|
+
if (Array.isArray(input.blocks)) out.blocks = input.blocks;
|
|
53081
|
+
return out;
|
|
53082
|
+
}
|
|
52960
53083
|
function narrowUpdatePost(input) {
|
|
52961
|
-
const out =
|
|
53084
|
+
const out = narrowCommonPostFields(input);
|
|
52962
53085
|
if (typeof input.title === "string") out.title = input.title;
|
|
52963
53086
|
if (typeof input.status === "string") out.status = input.status;
|
|
52964
|
-
if (typeof input.slug === "string") out.slug = input.slug;
|
|
52965
|
-
if (typeof input.parent === "number") out.parent = input.parent;
|
|
52966
|
-
if (typeof input.excerpt === "string") out.excerpt = input.excerpt;
|
|
52967
|
-
if (typeof input.featured_media === "number") out.featured_media = input.featured_media;
|
|
52968
|
-
if (Array.isArray(input.categories)) out.categories = input.categories.filter((n) => typeof n === "number");
|
|
52969
|
-
if (Array.isArray(input.tags)) out.tags = input.tags.filter((n) => typeof n === "number");
|
|
52970
|
-
if (input.terms && typeof input.terms === "object" && !Array.isArray(input.terms)) {
|
|
52971
|
-
out.terms = narrowTermsMap(input.terms);
|
|
52972
|
-
}
|
|
52973
|
-
if (typeof input.date === "string") out.date = input.date;
|
|
52974
|
-
if (typeof input.menu_order === "number") out.menu_order = input.menu_order;
|
|
52975
|
-
if (input.comment_status === "open" || input.comment_status === "closed") out.comment_status = input.comment_status;
|
|
52976
|
-
if (input.ping_status === "open" || input.ping_status === "closed") out.ping_status = input.ping_status;
|
|
52977
|
-
if (typeof input.author === "number") out.author = input.author;
|
|
52978
53087
|
return out;
|
|
52979
53088
|
}
|
|
52980
53089
|
function narrowTermsMap(input) {
|
|
@@ -53084,8 +53193,8 @@ async function handleMediaTool(toolName, args, client) {
|
|
|
53084
53193
|
}
|
|
53085
53194
|
}
|
|
53086
53195
|
|
|
53087
|
-
// src/
|
|
53088
|
-
var
|
|
53196
|
+
// src/types.ts
|
|
53197
|
+
var YOAST_SCHEMA_PAGE_TYPES = [
|
|
53089
53198
|
"WebPage",
|
|
53090
53199
|
"ItemPage",
|
|
53091
53200
|
"AboutPage",
|
|
@@ -53099,7 +53208,7 @@ var SCHEMA_PAGE_TYPES = [
|
|
|
53099
53208
|
"RealEstateListing",
|
|
53100
53209
|
"SearchResultsPage"
|
|
53101
53210
|
];
|
|
53102
|
-
var
|
|
53211
|
+
var YOAST_SCHEMA_ARTICLE_TYPES = [
|
|
53103
53212
|
"Article",
|
|
53104
53213
|
"BlogPosting",
|
|
53105
53214
|
"SocialMediaPosting",
|
|
@@ -53111,15 +53220,20 @@ var SCHEMA_ARTICLE_TYPES = [
|
|
|
53111
53220
|
"Report",
|
|
53112
53221
|
"None"
|
|
53113
53222
|
];
|
|
53114
|
-
var
|
|
53223
|
+
var YOAST_ROBOTS_ADVANCED = ["noimageindex", "noarchive", "nosnippet"];
|
|
53224
|
+
|
|
53225
|
+
// src/tools/yoast.ts
|
|
53226
|
+
var SCHEMA_PAGE_TYPES = YOAST_SCHEMA_PAGE_TYPES;
|
|
53227
|
+
var SCHEMA_ARTICLE_TYPES = YOAST_SCHEMA_ARTICLE_TYPES;
|
|
53228
|
+
var ROBOTS_ADVANCED = YOAST_ROBOTS_ADVANCED;
|
|
53115
53229
|
var YOAST_FIELD_PROPERTIES = {
|
|
53116
53230
|
title: { type: "string", description: "SEO title (supports Yoast variables like %%title%%)." },
|
|
53117
53231
|
description: { type: "string", description: "Meta description." },
|
|
53118
53232
|
canonical: { type: "string", description: "Canonical URL override." },
|
|
53119
53233
|
focus_keyword: { type: "string", description: "Focus keyphrase." },
|
|
53120
53234
|
noindex: {
|
|
53121
|
-
type:
|
|
53122
|
-
description:
|
|
53235
|
+
type: "boolean",
|
|
53236
|
+
description: 'true=noindex, false=explicit index. Pass null to reset to the post-type default; omit to leave the current value unchanged. (Advertised as a single boolean type because some AI clients \u2014 e.g. Google Gemini \u2014 reject a "null" member in a type array; the handler still accepts an explicit null.)'
|
|
53123
53237
|
},
|
|
53124
53238
|
nofollow: { type: "boolean", description: "true=nofollow, false=follow." },
|
|
53125
53239
|
robots_advanced: {
|
|
@@ -53203,16 +53317,16 @@ var YOAST_TOOLS = [
|
|
|
53203
53317
|
async function handleYoastTool(toolName, args, client) {
|
|
53204
53318
|
switch (toolName) {
|
|
53205
53319
|
case "yoast_get_seo": {
|
|
53206
|
-
const postId = args.post_id;
|
|
53207
|
-
if (
|
|
53208
|
-
throw new Error('yoast_get_seo: "post_id"
|
|
53320
|
+
const postId = coercePostId(args.post_id, "yoast_get_seo");
|
|
53321
|
+
if (postId === void 0) {
|
|
53322
|
+
throw new Error('yoast_get_seo: "post_id" is required');
|
|
53209
53323
|
}
|
|
53210
53324
|
return client.getYoastSEO(postId);
|
|
53211
53325
|
}
|
|
53212
53326
|
case "yoast_update_seo": {
|
|
53213
|
-
const postId = args.post_id;
|
|
53214
|
-
if (
|
|
53215
|
-
throw new Error('yoast_update_seo: "post_id"
|
|
53327
|
+
const postId = coercePostId(args.post_id, "yoast_update_seo");
|
|
53328
|
+
if (postId === void 0) {
|
|
53329
|
+
throw new Error('yoast_update_seo: "post_id" is required');
|
|
53216
53330
|
}
|
|
53217
53331
|
const { post_id: _omit, ...rest } = args;
|
|
53218
53332
|
void _omit;
|
|
@@ -53232,10 +53346,12 @@ async function handleYoastTool(toolName, args, client) {
|
|
|
53232
53346
|
throw new Error("yoast_bulk_update_seo: each item in `posts` must be an object");
|
|
53233
53347
|
}
|
|
53234
53348
|
const obj = raw2;
|
|
53235
|
-
|
|
53236
|
-
|
|
53349
|
+
const id = coercePostId(obj.post_id, "yoast_bulk_update_seo");
|
|
53350
|
+
if (id === void 0) {
|
|
53351
|
+
throw new Error("yoast_bulk_update_seo: each item requires `post_id`");
|
|
53237
53352
|
}
|
|
53238
|
-
const { post_id:
|
|
53353
|
+
const { post_id: _omit, ...rest } = obj;
|
|
53354
|
+
void _omit;
|
|
53239
53355
|
items.push({ post_id: id, ...narrowYoastFields(rest) });
|
|
53240
53356
|
}
|
|
53241
53357
|
return client.bulkUpdateYoastSEO(items);
|
|
@@ -53609,7 +53725,6 @@ function describeExchangeFetchError(url3, err) {
|
|
|
53609
53725
|
return `Exchange failed: could not reach ${url3} (${reason}).${hint}`;
|
|
53610
53726
|
}
|
|
53611
53727
|
async function exchangeCode(site, code, fetchFn = fetch, timeoutMs = EXCHANGE_FETCH_TIMEOUT_MS) {
|
|
53612
|
-
const origin2 = new URL(site).origin;
|
|
53613
53728
|
let url3 = `${site}/?rest_route=/gk-block-api/v1/connect/exchange`;
|
|
53614
53729
|
const controller = new AbortController();
|
|
53615
53730
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -53636,8 +53751,11 @@ async function exchangeCode(site, code, fetchFn = fetch, timeoutMs = EXCHANGE_FE
|
|
|
53636
53751
|
`Exchange failed: the site redirected the request (HTTP ${res.status}); ensure --site is the canonical site URL.`
|
|
53637
53752
|
);
|
|
53638
53753
|
}
|
|
53754
|
+
const current = new URL(url3);
|
|
53639
53755
|
const next = new URL(location, url3);
|
|
53640
|
-
|
|
53756
|
+
const upgradesToStandardHttpsPort = next.port === "" || next.port === "443";
|
|
53757
|
+
const sameHostHttpsUpgrade = current.protocol === "http:" && next.protocol === "https:" && next.hostname === current.hostname && upgradesToStandardHttpsPort;
|
|
53758
|
+
if (next.origin !== current.origin && !sameHostHttpsUpgrade) {
|
|
53641
53759
|
throw new Error(
|
|
53642
53760
|
`Exchange failed: the site redirected to a different origin (${next.origin}); refusing to send the credential off-site.`
|
|
53643
53761
|
);
|
|
@@ -53962,16 +54080,6 @@ Fall back \u2014 add this to your Claude Code MCP config manually:`);
|
|
|
53962
54080
|
}
|
|
53963
54081
|
|
|
53964
54082
|
// src/index.ts
|
|
53965
|
-
function readEnv(primary, legacy) {
|
|
53966
|
-
const fromPrimary = process.env[primary];
|
|
53967
|
-
if (fromPrimary) return fromPrimary;
|
|
53968
|
-
const fromLegacy = process.env[legacy];
|
|
53969
|
-
if (fromLegacy) {
|
|
53970
|
-
console.error(`[block-mcp] DEPRECATED: ${legacy} is deprecated; rename to ${primary} in your MCP client config.`);
|
|
53971
|
-
return fromLegacy;
|
|
53972
|
-
}
|
|
53973
|
-
return void 0;
|
|
53974
|
-
}
|
|
53975
54083
|
var ALL_TOOLS = [
|
|
53976
54084
|
...DISCOVERY_TOOLS,
|
|
53977
54085
|
...READ_TOOLS,
|
|
@@ -54002,13 +54110,16 @@ for (const { tools, handle: handle2 } of TOOL_GROUPS) {
|
|
|
54002
54110
|
}
|
|
54003
54111
|
var AGENT_GUIDE_RESOURCE_URI = "block-mcp://agent-guide";
|
|
54004
54112
|
var LEGACY_PREFERENCES_RESOURCE_URI = "block-mcp://block-preferences";
|
|
54005
|
-
function registerHandlers(server, client) {
|
|
54113
|
+
function registerHandlers(server, client, notConfiguredMessage) {
|
|
54006
54114
|
server.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
54007
54115
|
return { tools: ALL_TOOLS };
|
|
54008
54116
|
});
|
|
54009
54117
|
server.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
54010
54118
|
const { name, arguments: args } = request.params;
|
|
54011
54119
|
const toolArgs = args ?? {};
|
|
54120
|
+
if (!client) {
|
|
54121
|
+
return buildNotConfiguredResult(notConfiguredMessage ?? "Block MCP is not configured.");
|
|
54122
|
+
}
|
|
54012
54123
|
try {
|
|
54013
54124
|
const handle2 = TOOL_DISPATCH.get(name);
|
|
54014
54125
|
if (!handle2) {
|
|
@@ -54134,23 +54245,28 @@ async function main() {
|
|
|
54134
54245
|
await runConnect(process.argv.slice(3));
|
|
54135
54246
|
process.exit(0);
|
|
54136
54247
|
}
|
|
54137
|
-
const
|
|
54138
|
-
|
|
54139
|
-
|
|
54140
|
-
|
|
54248
|
+
const cfg = resolveWordPressConfig(process.env);
|
|
54249
|
+
if (!cfg.ok) {
|
|
54250
|
+
console.error(`Block MCP: ${cfg.message}`);
|
|
54251
|
+
const degraded = new McpServer(
|
|
54252
|
+
{ name: "block-mcp", version: package_default.version },
|
|
54253
|
+
{ capabilities: { tools: {}, resources: {}, prompts: {} } }
|
|
54254
|
+
);
|
|
54255
|
+
registerHandlers(degraded, null, cfg.message);
|
|
54256
|
+
await degraded.connect(new StdioServerTransport());
|
|
54141
54257
|
console.error(
|
|
54142
|
-
"
|
|
54258
|
+
"Block MCP Server running on stdio (unconfigured \u2014 tool calls return a configuration error)"
|
|
54143
54259
|
);
|
|
54144
|
-
|
|
54260
|
+
return;
|
|
54145
54261
|
}
|
|
54146
54262
|
const client = new WordPressBlockClient({
|
|
54147
|
-
wordpress_url:
|
|
54263
|
+
wordpress_url: cfg.config.url,
|
|
54148
54264
|
auth: {
|
|
54149
|
-
username:
|
|
54150
|
-
application_password:
|
|
54265
|
+
username: cfg.config.user,
|
|
54266
|
+
application_password: cfg.config.password
|
|
54151
54267
|
}
|
|
54152
54268
|
});
|
|
54153
|
-
const instructions = await getInstructions(
|
|
54269
|
+
const instructions = await getInstructions(cfg.config.url);
|
|
54154
54270
|
const server = new McpServer(
|
|
54155
54271
|
{
|
|
54156
54272
|
name: "block-mcp",
|