Koskamo

Moving Polygons MCP

An official MCP server for Moving Polygons that enables AI agents to interact with user accounts to create, edit, list, and publish animated historical maps. It supports tools for managing map drafts, uploading large files in parts, and searching public maps without authentication.

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.

Moving Polygons MCP logo, by Moving PolygonsVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-01Operated by Moving Polygons
You need:OAuth sign-in with a Moving Polygons account
MCP endpoint (Streamable HTTP)
https://www.movingpolygons.com/mcp
Vendor documentation

What you can do with it

  • Create animated historical maps from natural language descriptions
  • List and manage user's private map drafts
  • Publish or unpublish maps to the public library
  • Search for public maps by topic, place, or period

Source and maintenance

Vendor evidenceRegistry 1.0.0

Protocol and capabilities

Server
moving-polygons 1.0.0
MCP protocol
2025-06-18
Tools
14 advertised
Resources
1 advertised
Resource templates
0 advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "resources": {
    "listChanged": true
  }
}

Server-provided instructions

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

Moving Polygons (movingpolygons.com) turns timed polygons into animated maps: borders that morph between keyframes, plus point markers. Most tools act on the user's own account; the first call to one of them asks the user to sign in. search_maps, get_public_map and get_import_format work without signing in. Workflow for a new map: 1. Call get_import_format once and follow it exactly (geometry is a list of closed rings, not GeoJSON; labels ≤ 50 chars; colours #RRGGBB). 2. Small maps (under ~1 MB of JSON): pass the JSON object to create_map. 3. Bigger maps, or a map file you built in a sandbox or on disk: call create_upload_link, then run the returned curl command. Never paste a large file into a single tool call. If curl cannot reach this site (the claude.ai sandbox blocks it unless the user allowlists www.movingpolygons.com), send the minified JSON in parts of about 30,000 characters: start_map_upload, then upload_map_part for each piece in order, then finish_map_upload. 4. Give the user the editor or preview link. New maps are private drafts. To find maps other people published (any topic or period), use search_maps and get_public_map. Never call publish_map unless the user asked to publish: it makes the map public. replace_map_content overwrites a map (a backup is kept); confirm with the user first when the map is published.

Tools

14 advertised

get_import_format — Get the map import format
Advertised by the server during the last successful anonymous check.
Advertised read-only

The JSON format for maps: layers with timed polygon keyframes, point markers and a style.

get_import_format input schema
{
  "type": "object",
  "properties": {}
}
get_import_format annotations
{
  "readOnlyHint": true
}
get_account — Get account
Advertised by the server during the last successful anonymous check.
Advertised read-only

The signed-in user's public handle, plan and how many maps they can still create.

get_account input schema
{
  "type": "object",
  "properties": {}
}
get_account annotations
{
  "readOnlyHint": true
}
list_maps — List my maps
Advertised by the server during the last successful anonymous check.
Advertised read-only

The user's maps, most recently changed first, with their ids and links.

list_maps input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "limit": {
      "type": "integer",
      "maximum": 100,
      "minimum": 1,
      "description": "Default 50"
    },
    "search": {
      "type": "string",
      "description": "Only maps whose name contains this text"
    }
  }
}
list_maps annotations
{
  "readOnlyHint": true
}
get_map — Get a map
Advertised by the server during the last successful anonymous check.
Advertised read-only

A summary of one of the user's maps (layers, keyframe dates, markers) and a 15-minute download link for its full import JSON, which can be several MB.

get_map input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "mapId"
  ],
  "properties": {
    "mapId": {
      "type": "string",
      "description": "The map id"
    }
  }
}
get_map annotations
{
  "readOnlyHint": true
}
create_map — Create a map
Advertised by the server during the last successful anonymous check.

Create a new private draft map from an import JSON of up to about 1 MB.

create_map input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "map"
  ],
  "properties": {
    "map": {
      "anyOf": [
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        },
        {
          "type": "string"
        }
      ],
      "description": "The map in the Moving Polygons import format, as a JSON object or a JSON string"
    }
  }
}
create_map annotations
{
  "readOnlyHint": false,
  "idempotentHint": false,
  "destructiveHint": false
}
create_upload_link — Create an upload link
Advertised by the server during the last successful anonymous check.
Advertised read-only

A one-off link (valid 15 minutes) for uploading a map JSON file of up to 40 MB with curl. It creates a new draft map, or with mode replace overwrites an existing map's content. The curl output reports the result.

create_upload_link input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "mode": {
      "enum": [
        "create",
        "replace"
      ],
      "type": "string",
      "description": "create (default): a new map. replace: overwrite mapId's content"
    },
    "mapId": {
      "type": "string",
      "description": "Required for mode replace"
    }
  }
}
create_upload_link annotations
{
  "readOnlyHint": true
}
start_map_upload — Start a chunked map upload
Advertised by the server during the last successful anonymous check.

Opens an upload (valid 2 hours) for a map JSON text that is sent in numbered parts through tool calls rather than over the network. It creates a new draft map, or with mode replace overwrites an existing map's content.

start_map_upload input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "mode": {
      "enum": [
        "create",
        "replace"
      ],
      "type": "string",
      "description": "create (default): a new map. replace: overwrite mapId's content"
    },
    "mapId": {
      "type": "string",
      "description": "Required for mode replace"
    }
  }
}
start_map_upload annotations
{
  "readOnlyHint": false,
  "idempotentHint": false,
  "destructiveHint": false
}
upload_map_part — Upload one part of a map
Advertised by the server during the last successful anonymous check.

Stores one numbered piece of a chunked map upload. The pieces are joined in part order with nothing in between; sending a part number again replaces that part. Returns the piece's length and SHA-256.

upload_map_part input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "uploadId",
    "part",
    "text"
  ],
  "properties": {
    "part": {
      "type": "integer",
      "maximum": 400,
      "minimum": 1,
      "description": "1 for the first piece"
    },
    "text": {
      "type": "string",
      "maxLength": 250000,
      "description": "This piece of the map JSON text, verbatim"
    },
    "uploadId": {
      "type": "string"
    }
  }
}
upload_map_part annotations
{
  "readOnlyHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
finish_map_upload — Finish a chunked map upload
Advertised by the server during the last successful anonymous check.
Advertised destructive

Joins parts 1 to the given count of a chunked upload, validates the map and creates the draft map (or replaces the map's content, keeping a backup). Reports missing parts or where the JSON breaks.

finish_map_upload input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "uploadId",
    "parts"
  ],
  "properties": {
    "parts": {
      "type": "integer",
      "maximum": 400,
      "minimum": 1,
      "description": "How many parts were sent"
    },
    "uploadId": {
      "type": "string"
    }
  }
}
finish_map_upload annotations
{
  "readOnlyHint": false,
  "idempotentHint": false,
  "destructiveHint": true
}
replace_map_content — Replace a map's content
Advertised by the server during the last successful anonymous check.
Advertised destructive

Overwrite an existing map's layers, markers, name, description and casualty bar (and style, if given) with an import JSON of up to about 1 MB. The link and publish state stay; the old content is backed up.

replace_map_content input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "mapId",
    "map"
  ],
  "properties": {
    "map": {
      "anyOf": [
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {}
        },
        {
          "type": "string"
        }
      ],
      "description": "The map in the Moving Polygons import format, as a JSON object or a JSON string"
    },
    "mapId": {
      "type": "string"
    }
  }
}
replace_map_content annotations
{
  "readOnlyHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
publish_map — Publish a map
Advertised by the server during the last successful anonymous check.
Open-world

Make one of the user's maps public at its /map/<handle>/<slug> link, where anyone can view it. The user must first choose a username at https://www.movingpolygons.com/settings; until then this fails and says so.

publish_map input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "mapId"
  ],
  "properties": {
    "mapId": {
      "type": "string"
    }
  }
}
publish_map annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "destructiveHint": false
}
unpublish_map — Unpublish a map
Advertised by the server during the last successful anonymous check.

Make one of the user's maps private again (its public link stops working).

unpublish_map input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "mapId"
  ],
  "properties": {
    "mapId": {
      "type": "string"
    }
  }
}
unpublish_map annotations
{
  "readOnlyHint": false,
  "destructiveHint": false
}
search_maps — Search published maps
Advertised by the server during the last successful anonymous check.
Advertised read-only

Find published animated maps on Moving Polygons (history, wars, empires, borders, epidemics, sea ice…) by words in their title or description and/or a year they cover. Returns links to the interactive map, its text version and its article.

search_maps input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "year": {
      "type": "integer",
      "maximum": 9007199254740991,
      "minimum": -9007199254740991,
      "description": "Only maps whose timeline includes this year; negative for BC (-44 = 44 BC)"
    },
    "limit": {
      "type": "integer",
      "maximum": 50,
      "minimum": 1,
      "description": "Default 10"
    },
    "query": {
      "type": "string",
      "description": "Words to match, e.g. 'Ottoman', 'Holy Roman Empire', 'Ukraine war'"
    }
  }
}
search_maps annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
get_public_map — Get a published map
Advertised by the server during the last successful anonymous check.
Advertised read-only

One published map as Markdown: description and sources, the timeline of keyframes (date and caption), layers, events, and the iframe code to embed the interactive map. Pass its URL, or the handle and slug.

get_public_map input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "url": {
      "type": "string",
      "description": "e.g. https://www.movingpolygons.com/map/chrisjager/the-ottoman-empire-12991923"
    },
    "slug": {
      "type": "string",
      "description": "The last part of the map's URL, e.g. the-ottoman-empire-12991923"
    },
    "username": {
      "type": "string",
      "description": "The map owner's handle, e.g. chrisjager (with slug, instead of url)"
    }
  }
}
get_public_map annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

1 advertised

import-format — Map import format

Advertised by the server during the last successful anonymous check.

The JSON format for Moving Polygons maps

import-format URI
moving-polygons://import-format

MIME type: text/markdown

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
1127 ms
95th percentile latency
1127 ms

Maintenance history

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

  • · probe · passed · 1127 ms · metadata changed · 14 tool(s), 1 resource(s), 0 resource template(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 moving-polygons-mcp https://www.movingpolygons.com/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 moving-polygons-mcp --url https://www.movingpolygons.com/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable moving-polygons-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "moving-polygons-mcp": {
      "url": "https://www.movingpolygons.com/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "moving-polygons-mcp": {
      "type": "streamableHttp",
      "url": "https://www.movingpolygons.com/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start moving-polygons-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "moving-polygons-mcp": {
      "type": "http",
      "url": "https://www.movingpolygons.com/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 moving-polygons-mcp https://www.movingpolygons.com/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": {
    "moving-polygons-mcp": {
      "url": "https://www.movingpolygons.com/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": {
    "moving-polygons-mcp": {
      "serverUrl": "https://www.movingpolygons.com/mcp"
    }
  }
}

Let your agent find its tools

Find servers like Moving Polygons 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 Moving Polygons 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