3. With an AI agent
freemapper-print comes with an MCP server. Through it an AI agent such as Claude Code can read and check a project, write masks, number positions, layouts and sheet elements into the project file, and write the PDFs. You tell the agent in your own words what you need, for example "turn the training into window orienteering with 12 mm windows", and it calls the tools that do it. The server calls no language model itself. It does what the command-line commands do and returns their messages.
Setting it up
freemapper-print mcp starts the server. It reads requests from standard input and answers on standard output until the agent closes the connection. You do not start it by hand; the agent's program does. For Claude Code, put a file .mcp.json into the folder you start Claude Code in, for example the folder with your events:
{
"mcpServers": {
"freemapper-print": {
"command": "/home/user/bin/freemapper-print",
"args": ["--lang", "en", "mcp"]
}
}
}
command is the absolute path of the program, wherever you unpacked it (README, section "Installation"). On Windows it reads like C:\\Users\\name\\freemapper-print\\freemapper-print.exe, with double backslashes because the file is JSON. --lang en picks English messages; without it the system language applies, as on the command line. After the next start of Claude Code, /mcp shows the server with its thirteen tools.
Let the agent set it up
An agent that can run commands, such as Claude Code or Codex, also does the download, the check, the unpacking and the registration of the server. It follows AGENTS.md, which sits next to the program in the archive. Say, for example: "Read AGENTS.md from github.com/HenryJobst/freemapper-print and set up freemapper-print." On macOS it removes the block on unsigned programs and tells you so. Depending on its settings it asks before each command. Claude Desktop runs no commands; there you register the server yourself, as described above.
The tools
Every tool also takes lang ("de" or "en") to pick another language for that one call. project is the project folder or the file freemapper-print.toml in it.
| Tool | Like | Required | Optional | Result |
|---|---|---|---|---|
project_info | project | title, map kind and scale, map and course file, layouts with their elements, courses with layout and masks, the masks and the assignments | ||
check_project | check | project | the notes of each sheet with kind, severity (info, warning, error), course and message; needs_attention is true when check would end with exit code 1 | |
list_courses | project | the courses of the course file with number of controls, layout and masks | ||
init_project | init | folder, map | title, kind, courses | the layouts written, where the map kind came from, and the messages of init |
masks_window | masks window | project, course | controls, radius, radius_for, gap, no_start, no_finish, id, assign | the mask id, the windows and the messages |
masks_corridor | masks corridor | project, points | width, id, assign, course | the mask id and the messages |
numbers_accept | numbers accept | project, course, control, scope (sheet or layout_wide) | direction and gap, only together | the correction written and the message |
set_layout | project, id | paper, page_mm, orientation, print_scale, centre_map_mm, margin_mm, border_mm, crop, north_lines, hide_parts, hide_shared | the layout as the file now holds it, and change | |
set_element | project, id, kind, anchor | layout, lines, size_pt, box_white, file, width_mm, cell_mm | the element and change | |
assign_mask | project, course | mask, layout | the assignment and change | |
export_project | export | project, out_dir | courses, layouts, single_file | the PDFs written with their size, the notes of the sheets and the reminder to print at actual size |
check_update | update --check | whether a newer version exists, with the version numbers and the release notes | ||
install_update | update --yes | confirm | Installs only with confirm set to true; without it the tool returns an error. Installs the newest release and says that the running server keeps the old version until it is restarted |
The inputs are named like the options of the commands (chapters 5, 8 and 11) and the keys of the project file (chapters 6 and 7), with underscores: radius_for for --radius-for, points as the text "x,y;x,y" as with --points. change says whether the tool added something (added), changed it (changed) or had nothing to do (unchanged).
set_layout changes only the keys the call names; the others keep their value, and a new layout gets the defaults for them. null for print_scale prints at the map scale again, and for centre_map_mm it centres the map frame again. Only set_element changes the elements of a layout. It replaces the element with the same id as a whole; without layout the element is shared by all layouts ([[shared]]). A logo names its file by absolute path, and the project file stores it relative to itself. assign_mask sets the mask of a course even when it has one already; without mask the course prints without one. masks_window and masks_corridor with assign replace no mask.
check_update and install_update need no project. check_update says whether a newer version exists. install_update installs it only with confirm set to true and returns "Nothing was installed. Ask the person first, then call install_update with confirm: true once they agree." without it. The first result of a server session carries a note when a newer version exists. The agent passes it on and asks you before it installs. A server keeps running the old version after an install until the assistant restarts it.
The results are JSON. The tools that write return in messages the sentences the command prints on the command line. Where the command names an option, the server names the tool and the input: "Call check_project to see the result" instead of "Run check to see the result".
Rules
- All paths are absolute. The server does not know the agent's working folder, so it refuses a relative path with a message that says so.
~counts as relative. - When something goes wrong, the message is the one the command line would print, and the project file stays as it was. The tools that change layouts, elements and assignments check the changed file before they write it. An export that fails at one sheet keeps the PDFs it wrote before, and its message names them.
- An input the tool does not know is an error that names it, so a typo such as
print_scaldoes not pass as a call that changed nothing. - Writes happen one after the other. All tools that write, and
export_project, wait for each other, also when the agent calls several at once, so each call sees what the one before wrote.project_info,check_projectandlist_coursesdo not wait. - Comments in the project file stay, with three exceptions. A key whose value changes gets a new line, so a comment at the end of that line is lost, and so is one inside a value that spans several lines, such as between the entries of
lines = [ … ]. A sub-table such as[layouts.map_frame]or[layouts.elements.anchor]becomes one line in the short formmap_frame = { … }: the comment lines above and inside it move above that line, and comments at the end of its lines are lost. When the key goes away instead, its comments go with it. A new line also loses the indentation of the old one. - When the project file is a link, the server does not change it and says so. The command line replaces the link with a file in that case, which an agent would not notice. A project folder that is a link works.
export_projectwrites intoout_dir, a folder that exists already. It replaces a PDF of the same name there.layoutsdoes not go withcoursesorsingle_file.- Results stay small for large course files.
export_projectlists at most 200 files,check_project200 sheets,project_info200 courses, mask variants and assignments,list_courses200 courses, andinit_project200 course names over its layouts.check_projectandexport_projectreturn at most 200 notes.more_files,more_sheets,more_courses,more_masks,more_assignmentsandmorecount the rest.needs_attentioncovers every sheet, also those left out, andmore_sheets_needing_attentioncounts the sheets left out that need attention. - Only
export_projectcan be cancelled. When the agent cancels the call, the export stops after the sheet it is drawing. The PDFs before it stay whole, and no partial file is left. Withsingle_fileno PDF is written then. When the agent closes the connection, the server draws for up to five more seconds and then stops the same way. The other tools run to the end. Forcheck_projecton a very large course file (1000 courses of 200 controls each) that takes almost two minutes. A tool that writes and is cancelled while it waits for another write changes nothing. Closing the connection counts as a cancel: a write sent just before the agent closes it may be left out. After such a session,project_infoshows what the file holds. - Standard output belongs to the protocol. Errors of the server itself go to standard error.
What no tool changes, such as [event], [print] or an existing correction under [[numbers]], the agent changes in the file with its own means, or you do. check_project then shows whether the file still holds.
An example
The example examples/rummelsburg-mcp-session records a real session. The request to the agent is roughly: "Turn it into window orienteering with 12 mm windows and put the PDF into the folder out." The map and course T (8 controls, 2.0 km) are already in the folder.
init_projectcreates the project from the map and the course file, withkind"sprint". The result reports one layouta4-4000with course "T", andfitsis false: no sheet shows the whole map.check_projectreports three warnings, andneeds_attentionis true. On the A4 sheet the title block covers the start, the number of control 31 covers the line symbol 520.1 of the map, and every sheet carries the note that the font Arimo replaces Calibri.set_layoutswitches the layout to A3. The layout ida4-4000stays, becauseset_layoutrenames nothing.masks_windowwithcourse"T",radius12 andassignwrites the maskwindow-Twith ten windows around start, controls 31 to 38 and finish, and gives it to the course. No window gets smaller, because no two points of the course lie closer than 134 m.check_projectno longer reports the title block. The font and the number of control 31 remain, soneeds_attentionstays true. The agent exports anyway.export_projectwritesT.pdf(1,091,820 bytes, A3 landscape, 1:4000) and reminds you to print at actual size.
The session ran with a build after version 0.8.0 that already keeps the gap between windows (ADR 0063).