Koskamo

LocalSchema MCP

An MCP server that allows AI agents to generate, validate, and audit LocalBusiness JSON-LD structured data for local SEO. It supports free tools for schema generation and validation without authentication, and offers Pro account tools for managing client locations, publishing schema, and running health checks when a Pro API key is provided.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

LocalSchema MCP logo, by LocalSchemaVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-01Operated by LocalSchema
You need:Pro API key sent as the HTTP header "Authorization: Bearer ls_…" or "X-API-Key: ls_…"
MCP endpoint (Streamable HTTP)
https://local-schema-beacon.lovable.app/mcp
Vendor documentation

What you can do with it

  • Generate valid LocalBusiness JSON-LD markup for specific business types
  • Validate existing JSON-LD or HTML pages against schema.org guidelines
  • Audit live web pages for structured data health and errors
  • Manage client locations and publish schema via Pro API keys

Source and maintenance

Vendor evidenceRegistry 1.0.0

Protocol and capabilities

Server
local-schema-beacon 1.0.0
MCP protocol
2025-06-18
Tools
11 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": false
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

LocalSchema generates, validates and hosts LocalBusiness JSON-LD (schema.org structured data) for local businesses and the agencies that run their local SEO. Free tools, no key: list_business_types, generate_schema, validate_schema, validate_page, get_embed_snippet. Account tools (list_clients, save_client, list_locations, get_location, save_location, run_health_check) need a LocalSchema Pro API key sent as the HTTP header "Authorization: Bearer ls_…" or "X-API-Key: ls_…" in the MCP client's connection settings. Keys are created under Settings → API keys at https://local-schema-beacon.lovable.app/app/settings. Never ask for the key in chat and never pass it as a tool argument. Adding markup to a site: pick the most specific businessType (list_business_types), call generate_schema, fix every issue with severity error, insert script_tag into the page <head>, then call validate_page on the deployed URL. Managing client sites: save_location with publish: true, install the returned embed script_tag once on the client's site, then run_health_check. Later edits only need save_location with publish: true — the embed updates the site automatically. Opening hours use 24-hour HH:MM with day names or ranges ("Mo-Fr"); days not listed are closed; add two entries for split hours.

Tools

11 advertised

list_business_types — List business types
Advertised by the server during the last successful anonymous check.
Advertised read-only

List the schema.org LocalBusiness subtypes LocalSchema supports (Dentist, Plumber, Restaurant, …). Use the most specific one as businessType.

list_business_types input schema
{
  "type": "object",
  "properties": {}
}
list_business_types annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
generate_schema — Generate LocalBusiness schema
Advertised by the server during the last successful anonymous check.
Advertised read-only

Generate LocalBusiness JSON-LD (schema.org) from business details and validate it against Google's rich result rules. Returns the JSON-LD, a ready-to-paste <script> tag and issues to fix. No API key needed.

generate_schema input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "name"
  ],
  "properties": {
    "geo": {
      "type": "object",
      "required": [
        "latitude",
        "longitude"
      ],
      "properties": {
        "latitude": {
          "type": "number",
          "maximum": 90,
          "minimum": -90
        },
        "longitude": {
          "type": "number",
          "maximum": 180,
          "minimum": -180
        }
      }
    },
    "url": {
      "type": "string",
      "maxLength": 2000,
      "description": "Website URL (https://…)"
    },
    "logo": {
      "type": "string",
      "maxLength": 2000
    },
    "menu": {
      "type": "string",
      "maxLength": 2000
    },
    "name": {
      "type": "string",
      "maxLength": 200,
      "minLength": 1,
      "description": "Public business name"
    },
    "email": {
      "type": "string",
      "maxLength": 200
    },
    "hasMap": {
      "type": "string",
      "maxLength": 2000
    },
    "images": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 2000
      },
      "maxItems": 20
    },
    "rating": {
      "type": "object",
      "required": [
        "ratingValue",
        "reviewCount"
      ],
      "properties": {
        "bestRating": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "ratingValue": {
          "type": "number",
          "maximum": 100,
          "minimum": 0
        },
        "reviewCount": {
          "type": "integer",
          "maximum": 9007199254740991,
          "minimum": 0
        }
      },
      "description": "LocalSchema Pro — omitted from free output"
    },
    "sameAs": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 2000
      },
      "maxItems": 30,
      "description": "Google Business Profile, Yelp, Facebook, LinkedIn… profile URLs"
    },
    "slogan": {
      "type": "string",
      "maxLength": 200
    },
    "address": {
      "type": "object",
      "properties": {
        "postalCode": {
          "type": "string",
          "maxLength": 20
        },
        "addressRegion": {
          "type": "string",
          "maxLength": 120
        },
        "streetAddress": {
          "type": "string",
          "maxLength": 200
        },
        "addressCountry": {
          "type": "string",
          "maxLength": 60,
          "description": "ISO 3166-1 alpha-2, e.g. NL or US"
        },
        "addressLocality": {
          "type": "string",
          "maxLength": 120
        }
      }
    },
    "reviews": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "author",
          "rating"
        ],
        "properties": {
          "body": {
            "type": "string",
            "maxLength": 2000
          },
          "author": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "rating": {
            "type": "number",
            "maximum": 100,
            "minimum": 0
          },
          "datePublished": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          }
        }
      },
      "maxItems": 20,
      "description": "LocalSchema Pro — omitted from free output"
    },
    "services": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 2000
          },
          "name": {
            "type": "string",
            "maxLength": 120,
            "minLength": 1
          },
          "price": {
            "type": "number",
            "minimum": 0
          },
          "priceMax": {
            "type": "number",
            "minimum": 0
          },
          "unitText": {
            "type": "string",
            "maxLength": 40
          },
          "priceType": {
            "enum": [
              "fixed",
              "from",
              "range"
            ],
            "type": "string"
          },
          "description": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "maxItems": 50
    },
    "legalName": {
      "type": "string",
      "maxLength": 200
    },
    "telephone": {
      "type": "string",
      "maxLength": 40,
      "description": "International format, e.g. +31 50 123 4567"
    },
    "areaServed": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 120
      },
      "maxItems": 50
    },
    "priceRange": {
      "type": "string",
      "maxLength": 30,
      "description": "e.g. €€ or €20-€80"
    },
    "description": {
      "type": "string",
      "maxLength": 2000
    },
    "businessType": {
      "type": "string",
      "default": "LocalBusiness",
      "maxLength": 60,
      "description": "schema.org type, e.g. Dentist, Plumber, Restaurant. See /business-types."
    },
    "foundingDate": {
      "type": "string",
      "pattern": "^\\d{4}(-\\d{2}-\\d{2})?$"
    },
    "openingHours": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "days"
        ],
        "properties": {
          "days": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "description": "Day names or ranges: \"Mo-Fr\", [\"Saturday\"]"
          },
          "opens": {
            "type": "string",
            "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
          },
          "allDay": {
            "type": "boolean",
            "description": "Open 24 hours on these days"
          },
          "closes": {
            "type": "string",
            "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
          }
        }
      },
      "maxItems": 21,
      "description": "Regular hours. Days not listed are closed. Use two entries for split hours."
    },
    "specialHours": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "validFrom"
        ],
        "properties": {
          "label": {
            "type": "string",
            "maxLength": 80
          },
          "opens": {
            "type": "string",
            "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
          },
          "closed": {
            "type": "boolean"
          },
          "closes": {
            "type": "string",
            "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
          },
          "validFrom": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "validThrough": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          }
        }
      },
      "maxItems": 30,
      "description": "Holiday exceptions (LocalSchema Pro — omitted from free output)"
    },
    "alternateName": {
      "type": "string",
      "maxLength": 200
    },
    "knowsLanguage": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 40
      },
      "maxItems": 20
    },
    "servesCuisine": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      },
      "maxItems": 20
    },
    "paymentAccepted": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      },
      "maxItems": 20
    },
    "serviceAreaOnly": {
      "type": "boolean",
      "description": "True for service-area businesses without a storefront (address is hidden)"
    },
    "medicalSpecialty": {
      "type": "string",
      "maxLength": 80
    },
    "currenciesAccepted": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 3,
        "minLength": 3
      },
      "maxItems": 10
    },
    "acceptsReservations": {
      "type": "boolean"
    },
    "isAcceptingNewPatients": {
      "type": "boolean"
    }
  },
  "additionalProperties": false
}
generate_schema annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
validate_schema — Validate schema markup
Advertised by the server during the last successful anonymous check.
Advertised read-only

Validate existing LocalBusiness structured data: paste JSON-LD, a <script type="application/ld+json"> tag or a whole HTML page. Reports errors, missing recommended fields and best-practice warnings. No API key needed.

validate_schema input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "code"
  ],
  "properties": {
    "code": {
      "type": "string",
      "maxLength": 600000,
      "minLength": 1,
      "description": "JSON-LD text, a script tag, or full page HTML"
    }
  },
  "additionalProperties": false
}
validate_schema annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
validate_page — Validate a live page
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Fetch a public web page and audit its structured data: every JSON-LD block and type, the LocalBusiness markup's errors and warnings, LocalSchema embeds on the page and concrete recommendations. No API key needed.

validate_page input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "url"
  ],
  "properties": {
    "url": {
      "type": "string",
      "maxLength": 2000,
      "minLength": 4,
      "description": "Public http(s) address, e.g. https://example.com/contact"
    }
  },
  "additionalProperties": false
}
validate_page annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "idempotentHint": true
}
get_embed_snippet — Get hosted embed snippet
Advertised by the server during the last successful anonymous check.
Advertised read-only

Get the install snippet and live status for a LocalSchema hosted embed key (loc_… for one location, org_… for a client with several). Paste the script tag once; published updates reach the site automatically.

get_embed_snippet input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "key"
  ],
  "properties": {
    "key": {
      "type": "string",
      "pattern": "^(?:loc|org)_[a-z0-9]{6,32}$",
      "description": "Hosted embed key"
    }
  },
  "additionalProperties": false
}
get_embed_snippet annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
list_clients — List clients
Advertised by the server during the last successful anonymous check.
Advertised read-only

List the agency's clients (brands) with their location counts, client-wide embed script and white-label report link. Needs a LocalSchema Pro API key in the request headers.

list_clients input schema
{
  "type": "object",
  "properties": {}
}
list_clients annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
save_client — Create or update a client
Advertised by the server during the last successful anonymous check.

Create a client (brand) or update one by client_id, and optionally turn its white-label health report link on or off. Needs a LocalSchema Pro API key in the request headers.

save_client input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "name": {
      "type": "string",
      "maxLength": 160,
      "minLength": 1,
      "description": "Client (brand) name. Required when creating; omit to keep it when updating."
    },
    "report": {
      "type": "boolean",
      "description": "true turns the client's white-label health report link on, false turns it off. Omit to leave it."
    },
    "website": {
      "type": "string",
      "maxLength": 500,
      "description": "Brand website; links every branch to one Organization in the client embed. When updating, omit to keep it or send \"\" to clear it."
    },
    "client_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "Update this client. Omit to create one."
    },
    "contact_name": {
      "type": "string",
      "maxLength": 160,
      "description": "Contact person. When updating, omit to keep it or send \"\" to clear it."
    },
    "contact_email": {
      "type": "string",
      "maxLength": 255,
      "description": "Contact email. When updating, omit to keep it or send \"\" to clear it."
    }
  },
  "additionalProperties": false
}
save_client annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": false,
  "destructiveHint": false
}
list_locations — List saved locations
Advertised by the server during the last successful anonymous check.
Advertised read-only

List the business locations saved in the LocalSchema account: publish state, hosted embed script, website and latest health check score. Needs a LocalSchema Pro API key in the request headers.

list_locations input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "properties": {
    "client_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "Only this client's locations"
    }
  },
  "additionalProperties": false
}
list_locations annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
get_location — Get a saved location
Advertised by the server during the last successful anonymous check.
Advertised read-only

Get one saved location: its business fields (in the same shape save_location accepts), the current JSON-LD, the published JSON-LD, validation issues and embed details. Needs a LocalSchema Pro API key in the request headers.

get_location input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "location_id"
  ],
  "properties": {
    "location_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "Location id from list_locations"
    }
  },
  "additionalProperties": false
}
get_location annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true
}
save_location — Save a location
Advertised by the server during the last successful anonymous check.

Save a business location to the LocalSchema account — create one, or update one by location_id (only the business fields you send change) — and optionally publish it to its hosted embed so the client's site updates without code changes. Needs a LocalSchema Pro API key in the request headers.

save_location input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "business"
  ],
  "properties": {
    "publish": {
      "type": "boolean",
      "description": "Publish to the hosted embed now. Default false (saved as a draft)."
    },
    "business": {
      "type": "object",
      "description": "Business fields in the same shape as generate_schema (name, businessType, address, openingHours, services, …). When updating, only the fields you send change; address merges field by field, lists are replaced.",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    },
    "client_id": {
      "anyOf": [
        {
          "type": "string",
          "format": "uuid",
          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
        },
        {
          "type": "null"
        }
      ],
      "description": "Assign to a client (see list_clients); null removes the assignment. Omit to keep the current client."
    },
    "location_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "Update this location. Omit to create a new one (counts toward the plan's location limit)."
    },
    "website_url": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 500
        },
        {
          "type": "null"
        }
      ],
      "description": "Page where the hosted embed is installed; health checks scan it. Defaults to business.url."
    }
  },
  "additionalProperties": false
}
save_location annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": false,
  "destructiveHint": false
}
run_health_check — Run a health check
Advertised by the server during the last successful anonymous check.
Open-world

Run a schema health check for a saved location: validates its markup, scans its website for the embed and conflicting hard-coded schema, detects unpublished changes and records the result in the dashboard and client reports. Needs a LocalSchema Pro API key in the request headers.

run_health_check input schema
{
  "type": "object",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "required": [
    "location_id"
  ],
  "properties": {
    "location_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "Location id from list_locations"
    }
  },
  "additionalProperties": false
}
run_health_check annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

Not advertised

No resource definitions available.

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
590 ms
95th percentile latency
590 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 590 ms · metadata changed · 11 tool(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http localschema-mcp https://local-schema-beacon.lovable.app/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add localschema-mcp --url https://local-schema-beacon.lovable.app/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable localschema-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "localschema-mcp": {
      "url": "https://local-schema-beacon.lovable.app/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "localschema-mcp": {
      "type": "streamableHttp",
      "url": "https://local-schema-beacon.lovable.app/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start localschema-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "localschema-mcp": {
      "type": "http",
      "url": "https://local-schema-beacon.lovable.app/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http localschema-mcp https://local-schema-beacon.lovable.app/mcp

Claude Desktop

Merge this into claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude Desktop.
Claude Desktop configuration
{
  "mcpServers": {
    "localschema-mcp": {
      "url": "https://local-schema-beacon.lovable.app/mcp"
    }
  }
}

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "localschema-mcp": {
      "serverUrl": "https://local-schema-beacon.lovable.app/mcp"
    }
  }
}

Let your agent find its tools

Find servers like LocalSchema MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run LocalSchema MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing