mcp-scraper 0.44.2 → 0.44.4

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/README.md CHANGED
@@ -90,7 +90,7 @@ Build the branded one-click bundle:
90
90
  npm run build:mcpb
91
91
  ```
92
92
 
93
- The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.44.2`, SHA-256 `6ce5675c82d1fa0b7c645e0337aaac97de7760282067e5744259e8d0a4f03fc2`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
93
+ The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.44.4`, SHA-256 `707dbcce1bafc04fc49f3a12cfc4ab43710e686e2f31102767ed120a3e8ff474`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
94
94
 
95
95
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
96
96
 
@@ -233,7 +233,7 @@ The `mcp-scraper` server (and the MCPB bundle, which runs it) exposes both secti
233
233
 
234
234
  All MCP tools expose output schemas and return `structuredContent` with the IDs, URLs, CSV paths, transcripts, browser session handles, replay paths, artifacts, recipe fields, or blueprint fields needed by the next step. Browser Agent tools keep a JSON text block for older clients, but structured data is the primary contract. All tools carry MCP annotations; file-writing tools such as replay downloads and annotations state their filesystem side effects.
235
235
 
236
- The canonical tool inventory is generated at `docs/mcp-tool-manifest.generated.json`. The unified server exposes 215 tools: 114 scraper, browser, workflow, billing, and connected-service tools plus 101 durable-memory tools. The scraper inventory includes governed Local Sourcebook tools that follow a Memory-style contract/tag/prepare/validate/capture sequence before paid acquisition, plus Transparent Commons tools for public entity search, planning, validation, governed contribution, ledgers, needs-link discovery, and saved filters. Local Sourcebook publication remains administrator-only. Release verification compares the exact local and hosted tool-name sets, not only the count.
236
+ The canonical tool inventory is generated at `docs/mcp-tool-manifest.generated.json`. The unified server exposes 215 tools: 114 scraper, browser, workflow, billing, and connected-service tools plus 101 durable-memory tools. The scraper inventory includes governed Local Sourcebook tools that follow a Memory-style contract/tag/prepare/validate/capture sequence before paid acquisition, plus Transparent Commons tools for public entity search, planning, validation, governed contribution, ledgers, needs-link discovery, and saved filters. Successful evidence-compiled Local Sourcebook revisions publish automatically to their canonical `localsourcebook.com` category profile and review URLs; administrator controls handle exceptional rejection or unpublishing. Release verification compares the exact local and hosted tool-name sets, not only the count.
237
237
 
238
238
  For contract parity, stdio and MCPB memory calls invoke the matching public tool on the hosted MCP Scraper `/mcp` endpoint. The hosted aggregate runtime owns MCP Scraper-specific billing, scheduling, credential, and in-process cutover policy; its internal `/memory/mcp-call` bridge is a fallback to the standalone memory service, not the public stdio execution path. Direct `mcp-memory` OAuth and stdio clients continue to use `memory.mcpscraper.dev` and must be verified as a separate dependent release surface.
239
239
 
@@ -24789,6 +24789,14 @@ async function listPublicLocalSourcebook(category, state) {
24789
24789
  const result = await getDb().execute({ sql: `SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.category = ? AND s.state = ? AND s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') ORDER BY s.business_name`, args: [category, state] });
24790
24790
  return result.rows.map((row) => parseJson2(row.payload_json));
24791
24791
  }
24792
+ async function listAllPublicLocalSourcebook(category) {
24793
+ await ensureLocalSourcebookSchema();
24794
+ const result = category ? await getDb().execute({
24795
+ sql: `SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.category = ? AND s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') ORDER BY s.state, s.business_name`,
24796
+ args: [category]
24797
+ }) : await getDb().execute(`SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') ORDER BY s.category, s.state, s.business_name`);
24798
+ return result.rows.map((row) => parseJson2(row.payload_json));
24799
+ }
24792
24800
  async function getPublicLocalSourcebook(category, state, slug2) {
24793
24801
  await ensureLocalSourcebookSchema();
24794
24802
  const result = await getDb().execute({ sql: `SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.category = ? AND s.state = ? AND s.slug = ? AND s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') LIMIT 1`, args: [category, state, slug2] });
@@ -25444,6 +25452,50 @@ var init_MapsExtractor = __esm({
25444
25452
  }
25445
25453
  });
25446
25454
 
25455
+ // src/api/local-sourcebook-public-urls.ts
25456
+ function rootDomain() {
25457
+ const configured = process.env.LOCAL_SOURCEBOOK_PUBLIC_ROOT_DOMAIN?.trim() || DEFAULT_ROOT_DOMAIN;
25458
+ return configured.replace(/^https?:\/\//i, "").replace(/^www\./i, "").replace(/\/.*$/, "").replace(/\.+$/, "").toLowerCase();
25459
+ }
25460
+ function localSourcebookPublicUrls(category, state, slug2) {
25461
+ const categoryUrl = `https://${CATEGORY_PUBLIC_SLUGS[category]}.${rootDomain()}`;
25462
+ const statePath = `/${state.toLowerCase()}`;
25463
+ const profilePath = `${statePath}/${slug2}/`;
25464
+ const reviewsPath = `${statePath}/${slug2}/reviews`;
25465
+ return {
25466
+ categoryUrl,
25467
+ nationwideDirectoryUrl: `${categoryUrl}/directory`,
25468
+ stateUrl: `${categoryUrl}${statePath}`,
25469
+ profileUrl: `${categoryUrl}${profilePath}`,
25470
+ reviewsUrl: `${categoryUrl}${reviewsPath}`,
25471
+ profilePath,
25472
+ reviewsPath
25473
+ };
25474
+ }
25475
+ function localSourcebookPublicationLinks(submission) {
25476
+ return {
25477
+ ...localSourcebookPublicUrls(submission.category, submission.state, submission.slug),
25478
+ publicationStatus: submission.status,
25479
+ isLive: submission.status === "published" && submission.publishedRevision !== null
25480
+ };
25481
+ }
25482
+ var DEFAULT_ROOT_DOMAIN, CATEGORY_PUBLIC_SLUGS;
25483
+ var init_local_sourcebook_public_urls = __esm({
25484
+ "src/api/local-sourcebook-public-urls.ts"() {
25485
+ "use strict";
25486
+ DEFAULT_ROOT_DOMAIN = "localsourcebook.com";
25487
+ CATEGORY_PUBLIC_SLUGS = {
25488
+ home: "home-services",
25489
+ professional: "professional",
25490
+ restaurants: "restaurants",
25491
+ financial: "financial",
25492
+ realestate: "realestate",
25493
+ auto: "auto",
25494
+ wellness: "wellness"
25495
+ };
25496
+ }
25497
+ });
25498
+
25447
25499
  // src/api/local-sourcebook-compiler.ts
25448
25500
  function digest(value) {
25449
25501
  return (0, import_node_crypto13.createHash)("sha256").update(value).digest("hex").slice(0, 20);
@@ -25719,6 +25771,7 @@ function compileLocalSourcebookListing(input) {
25719
25771
  evidenceIds: mapsEvidenceId ? [mapsEvidenceId] : []
25720
25772
  }
25721
25773
  ];
25774
+ const publicUrls = localSourcebookPublicUrls(input.submission.category, input.submission.state, input.submission.slug);
25722
25775
  const listing = {
25723
25776
  id: input.submission.id,
25724
25777
  publicationRevision: input.submission.draftRevision + 1,
@@ -25727,6 +25780,14 @@ function compileLocalSourcebookListing(input) {
25727
25780
  state: input.submission.state.toLowerCase(),
25728
25781
  stateName: STATE_NAMES[input.submission.state.toUpperCase()] ?? input.submission.state.toUpperCase(),
25729
25782
  slug: input.submission.slug,
25783
+ canonicalPaths: {
25784
+ profile: publicUrls.profilePath,
25785
+ reviews: publicUrls.reviewsPath
25786
+ },
25787
+ canonicalUrls: {
25788
+ profile: publicUrls.profileUrl,
25789
+ reviews: publicUrls.reviewsUrl
25790
+ },
25730
25791
  name: maps?.name || input.submission.businessName,
25731
25792
  summary,
25732
25793
  description,
@@ -25790,6 +25851,7 @@ var init_local_sourcebook_compiler = __esm({
25790
25851
  "src/api/local-sourcebook-compiler.ts"() {
25791
25852
  "use strict";
25792
25853
  import_node_crypto13 = require("crypto");
25854
+ init_local_sourcebook_public_urls();
25793
25855
  CATEGORY_LABELS = {
25794
25856
  home: "Home & property services",
25795
25857
  professional: "Professional services",
@@ -36621,7 +36683,11 @@ function getLocalSourcebookContract(category) {
36621
36683
  categories: LOCAL_SOURCEBOOK_CATEGORIES,
36622
36684
  selectedCategory: category ?? null,
36623
36685
  categoryTag: category ? CATEGORY_TAG[category] : null,
36624
- canonicalRoutes: { profile: "/{state}/{business-slug}/", reviews: "/{state}/{business-slug}/reviews" },
36686
+ canonicalRoutes: {
36687
+ nationwideDirectory: "https://{category}.localsourcebook.com/directory",
36688
+ profile: "https://{category}.localsourcebook.com/{state}/{business-slug}/",
36689
+ reviews: "https://{category}.localsourcebook.com/{state}/{business-slug}/reviews"
36690
+ },
36625
36691
  requiredCreateFields: ["category", "state", "businessName", "websiteUrl", "tags", "idempotencyKey"],
36626
36692
  systemCompiledSections: ["identity", "services/products", "service areas/locations", "genuine media", "reviews and theme counts", "evidence", "answered FAQ", "collection receipts"],
36627
36693
  workflow: ["list-local-sourcebook-tags", "get-local-sourcebook-contract", "prepare-local-sourcebook-write", "validate-local-sourcebook-write", "local-sourcebook-capture", "local_sourcebook_submission_status"],
@@ -36641,9 +36707,10 @@ async function prepareLocalSourcebookWrite(input) {
36641
36707
  ...parsed.tags.filter((tag) => tag !== categoryTag).map((tag) => ({ tag }))
36642
36708
  ];
36643
36709
  const tagResolutions = await resolveLocalSourcebookTags(candidates);
36710
+ const publicUrls = localSourcebookPublicUrls(parsed.category, parsed.state, slug2);
36644
36711
  return {
36645
36712
  ok: true,
36646
- route: { category: parsed.category, state: parsed.state, slug: slug2, profile: `/${parsed.state}/${slug2}/`, reviews: `/${parsed.state}/${slug2}/reviews` },
36713
+ route: { category: parsed.category, state: parsed.state, slug: slug2, ...publicUrls },
36647
36714
  proposedWrite: { ...parsed, slug: slug2, tags: tagResolutions.filter((item) => item.action === "reuse").map((item) => item.tag) },
36648
36715
  contract: getLocalSourcebookContract(parsed.category),
36649
36716
  tagResolutions,
@@ -36709,6 +36776,7 @@ var init_local_sourcebook_governance = __esm({
36709
36776
  import_zod29 = require("zod");
36710
36777
  init_db();
36711
36778
  init_local_sourcebook_repository();
36779
+ init_local_sourcebook_public_urls();
36712
36780
  DIRECTORY_TAG_SEEDS = [
36713
36781
  { tag: "home-services", description: "Businesses that maintain, repair, improve, or protect homes and property.", aliases: ["home service", "home and property services"] },
36714
36782
  { tag: "professional-services", description: "Local professional and business service providers.", aliases: ["professional service"] },
@@ -36759,6 +36827,18 @@ var init_local_sourcebook_governance = __esm({
36759
36827
  });
36760
36828
 
36761
36829
  // src/api/local-sourcebook-routes.ts
36830
+ function withCanonicalLocalSourcebookUrls(listing) {
36831
+ const category = import_zod30.z.enum(LOCAL_SOURCEBOOK_CATEGORIES).safeParse(listing.category);
36832
+ const state = typeof listing.state === "string" ? listing.state : "";
36833
+ const listingSlug = typeof listing.slug === "string" ? listing.slug : "";
36834
+ if (!category.success || !state || !listingSlug) return listing;
36835
+ const publicUrls = localSourcebookPublicUrls(category.data, state, listingSlug);
36836
+ return {
36837
+ ...listing,
36838
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
36839
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl }
36840
+ };
36841
+ }
36762
36842
  function acquisitionPlan(websiteUrl) {
36763
36843
  return {
36764
36844
  website: { startUrl: websiteUrl, mode: "broad_site_crawl", capture: ["homepage", "services", "products", "locations", "service_areas", "about", "team_staff", "contact", "policies"] },
@@ -36778,6 +36858,7 @@ var init_local_sourcebook_routes = __esm({
36778
36858
  init_local_sourcebook_dispatch();
36779
36859
  init_local_sourcebook_governance();
36780
36860
  init_local_sourcebook_repository();
36861
+ init_local_sourcebook_public_urls();
36781
36862
  slug = (value) => value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 100);
36782
36863
  SubmitSchema = import_zod30.z.object({
36783
36864
  category: import_zod30.z.enum(LOCAL_SOURCEBOOK_CATEGORIES),
@@ -36826,6 +36907,7 @@ var init_local_sourcebook_routes = __esm({
36826
36907
  return c.json({ error: "idempotency_key_required", message: "A stable idempotencyKey is required for a new Local Sourcebook capture." }, 400);
36827
36908
  }
36828
36909
  const listingSlug = identity.slug ?? slug(identity.businessName);
36910
+ const publicUrls = localSourcebookPublicUrls(identity.category, identity.state, listingSlug);
36829
36911
  const submission = await createLocalSourcebookSubmission({
36830
36912
  ownerUserId: Number(user.id),
36831
36913
  category: identity.category,
@@ -36842,7 +36924,8 @@ var init_local_sourcebook_routes = __esm({
36842
36924
  name: identity.businessName,
36843
36925
  websiteUrl: identity.websiteUrl,
36844
36926
  tags: validation.normalizedTags,
36845
- canonicalPaths: { profile: `/${identity.state}/${listingSlug}`, reviews: `/${identity.state}/${listingSlug}/reviews` },
36927
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
36928
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl },
36846
36929
  verificationState: "submitted",
36847
36930
  acquisitionPlan: acquisitionPlan(identity.websiteUrl),
36848
36931
  evidence: [],
@@ -36852,7 +36935,7 @@ var init_local_sourcebook_routes = __esm({
36852
36935
  });
36853
36936
  await persistLocalSourcebookTags(submission.id, Number(user.id), validation.normalizedTags, parsed.data.tagDecisions);
36854
36937
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
36855
- return c.json({ ok: true, valid: true, submission, normalizedTags: validation.normalizedTags, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(identity.websiteUrl) }, 202);
36938
+ return c.json({ ok: true, valid: true, submission, publicUrls: localSourcebookPublicationLinks(submission), normalizedTags: validation.normalizedTags, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(identity.websiteUrl) }, 202);
36856
36939
  } catch (error) {
36857
36940
  const message = error instanceof Error ? error.message : String(error);
36858
36941
  const conflict = message.includes("revision conflict") ? "revision_conflict" : message.includes("idempotency key conflicts") ? "idempotency_conflict" : null;
@@ -36866,6 +36949,7 @@ var init_local_sourcebook_routes = __esm({
36866
36949
  if (!parsed.success) return c.json({ error: "invalid_submission", issues: parsed.error.issues }, 400);
36867
36950
  const input = parsed.data;
36868
36951
  const listingSlug = input.slug ?? slug(input.businessName);
36952
+ const publicUrls = localSourcebookPublicUrls(input.category, input.state, listingSlug);
36869
36953
  try {
36870
36954
  const submission = await createLocalSourcebookSubmission({
36871
36955
  ownerUserId: Number(user.id),
@@ -36878,7 +36962,8 @@ var init_local_sourcebook_routes = __esm({
36878
36962
  slug: listingSlug,
36879
36963
  name: input.businessName,
36880
36964
  websiteUrl: input.websiteUrl,
36881
- canonicalPaths: { profile: `/${input.state}/${listingSlug}`, reviews: `/${input.state}/${listingSlug}/reviews` },
36965
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
36966
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl },
36882
36967
  verificationState: "submitted",
36883
36968
  acquisitionPlan: acquisitionPlan(input.websiteUrl),
36884
36969
  evidence: [],
@@ -36887,7 +36972,7 @@ var init_local_sourcebook_routes = __esm({
36887
36972
  }
36888
36973
  });
36889
36974
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
36890
- return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(input.websiteUrl) }, 202);
36975
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(input.websiteUrl) }, 202);
36891
36976
  } catch (error) {
36892
36977
  return c.json({ error: "submission_conflict", message: error instanceof Error ? error.message : String(error) }, 409);
36893
36978
  }
@@ -36896,7 +36981,7 @@ var init_local_sourcebook_routes = __esm({
36896
36981
  const userId = Number(c.get("user").id);
36897
36982
  const submission = await getLocalSourcebookSubmission(c.req.param("id"), userId);
36898
36983
  if (!submission) return c.json({ error: "not_found" }, 404);
36899
- return c.json({ ok: true, submission, draft: await getLocalSourcebookDraft(submission.id, userId) });
36984
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), draft: await getLocalSourcebookDraft(submission.id, userId) });
36900
36985
  });
36901
36986
  localSourcebookApp.on(["PATCH", "POST"], "/submissions/:id/draft", createApiKeyAuth(), (c) => c.json({
36902
36987
  error: "evidence_refresh_required",
@@ -36909,16 +36994,18 @@ var init_local_sourcebook_routes = __esm({
36909
36994
  const submission = await queueLocalSourcebookRefresh(c.req.param("id"), Number(user.id));
36910
36995
  if (!submission) return c.json({ error: "not_found" }, 404);
36911
36996
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
36912
- return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
36997
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
36913
36998
  } catch (error) {
36914
36999
  return c.json({ error: "moderated_listing", message: error instanceof Error ? error.message : String(error) }, 409);
36915
37000
  }
36916
37001
  });
36917
37002
  publicLocalSourcebookApp = new import_hono17.Hono();
36918
- publicLocalSourcebookApp.get("/:category/:state", async (c) => c.json({ ok: true, listings: await listPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase()) }));
37003
+ publicLocalSourcebookApp.get("/", async (c) => c.json({ ok: true, listings: (await listAllPublicLocalSourcebook()).map(withCanonicalLocalSourcebookUrls) }));
37004
+ publicLocalSourcebookApp.get("/:category", async (c) => c.json({ ok: true, listings: (await listAllPublicLocalSourcebook(c.req.param("category"))).map(withCanonicalLocalSourcebookUrls) }));
37005
+ publicLocalSourcebookApp.get("/:category/:state", async (c) => c.json({ ok: true, listings: (await listPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase())).map(withCanonicalLocalSourcebookUrls) }));
36919
37006
  publicLocalSourcebookApp.get("/:category/:state/:slug", async (c) => {
36920
37007
  const listing = await getPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase(), c.req.param("slug"));
36921
- return listing ? c.json({ ok: true, listing }) : c.json({ error: "not_found" }, 404);
37008
+ return listing ? c.json({ ok: true, listing: withCanonicalLocalSourcebookUrls(listing) }) : c.json({ error: "not_found" }, 404);
36922
37009
  });
36923
37010
  adminLocalSourcebookApp = new import_hono17.Hono();
36924
37011
  adminLocalSourcebookApp.use("*", adminAuth);
@@ -40932,7 +41019,7 @@ var PACKAGE_VERSION;
40932
41019
  var init_version = __esm({
40933
41020
  "src/version.ts"() {
40934
41021
  "use strict";
40935
- PACKAGE_VERSION = "0.44.2";
41022
+ PACKAGE_VERSION = "0.44.4";
40936
41023
  }
40937
41024
  });
40938
41025
 
@@ -41103,6 +41190,8 @@ Multi-step orchestrations \u2014 prefer these over hand-chaining primitives when
41103
41190
  publishes automatically. Never supply owner-authored services, reviews, images, or other public claims.
41104
41191
  - Read progress and the compiled record with **local_sourcebook_submission_status**. Use
41105
41192
  **local_sourcebook_refresh** only when the owner intentionally wants to pay for a new acquisition pass.
41193
+ - Capture and status responses return \`publicUrls.profileUrl\` and \`publicUrls.reviewsUrl\`. Always give those
41194
+ exact links to the user; do not report a listing as live without including its clickable profile URL.
41106
41195
  - The last published revision remains public during refresh. Administrators can reject or unpublish an
41107
41196
  exceptional record, but routine subscriber publication does not require administrator review.
41108
41197
 
@@ -45182,7 +45271,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
45182
45271
  }, async (input) => formatDirectoryWorkflow(await executor.directoryWorkflowStatus(input), input, ctx));
45183
45272
  server.registerTool("get-local-sourcebook-contract", {
45184
45273
  title: "Get Local Sourcebook Contract",
45185
- description: "Read the governed listing purpose, supported categories, canonical profile/review routes, required sections, acquisition limits, tag policy, ownership boundary, and admin-only publication rule. Call this before composing a listing when its required shape is uncertain.",
45274
+ description: "Read the governed listing purpose, supported categories, exact LocalSourcebook.com profile/review URLs, nationwide directory URL, required sections, acquisition limits, tag policy, ownership boundary, and automatic evidence-publication rule. Call this before composing a listing when its required shape is uncertain.",
45186
45275
  inputSchema: GetLocalSourcebookContractInputSchema,
45187
45276
  outputSchema: recordOutputSchema("get-local-sourcebook-contract", LocalSourcebookOutputSchema),
45188
45277
  annotations: localPlanningToolAnnotations("Get Local Sourcebook Contract")
@@ -45217,14 +45306,14 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
45217
45306
  }, async (input) => executor.validateLocalSourcebookWrite(input));
45218
45307
  server.registerTool("local-sourcebook-capture", {
45219
45308
  title: "Capture Governed Local Sourcebook Listing",
45220
- description: "Strict owner-scoped write path after list, contract, prepare, and validate. Capture registers canonical tags and queues paid website, exact-place, review, service-area, staff, and genuine-media acquisition. A successful system-compiled evidence revision publishes automatically; owner-authored public claims are not accepted.",
45309
+ description: "Strict owner-scoped write path after list, contract, prepare, and validate. Capture registers canonical tags, returns the exact LocalSourcebook.com profile and reviews URLs, and queues paid website, exact-place, review, service-area, staff, and genuine-media acquisition. A successful system-compiled evidence revision publishes automatically; owner-authored public claims are not accepted.",
45221
45310
  inputSchema: LocalSourcebookCaptureInputSchema,
45222
45311
  outputSchema: recordOutputSchema("local-sourcebook-capture", LocalSourcebookOutputSchema),
45223
45312
  annotations: liveWebToolAnnotations("Capture Governed Local Sourcebook Listing")
45224
45313
  }, async (input) => executor.localSourcebookCapture(input));
45225
45314
  server.registerTool("local_sourcebook_submission_status", {
45226
45315
  title: "Local Sourcebook Submission Status",
45227
- description: "Read the authenticated caller\u2019s listing draft, enrichment coverage, immutable revision number, and publication state.",
45316
+ description: "Read the authenticated caller\u2019s listing draft, enrichment coverage, immutable revision number, publication state, and exact live LocalSourcebook.com profile and reviews URLs.",
45228
45317
  inputSchema: LocalSourcebookSubmissionStatusInputSchema,
45229
45318
  outputSchema: recordOutputSchema("local_sourcebook_submission_status", LocalSourcebookOutputSchema),
45230
45319
  annotations: localPlanningToolAnnotations("Local Sourcebook Submission Status")