OpenGeoRock
5.1

MCP server

Describes OGR Slip2D 0.1.235

ogr-slip2d-mcp is the official Model Context Protocol (MCP) server of OGR Slip2D. With it, an AI agent can build a slope model, run the analysis and read and draw the results, either on models of the server's own or on the model open in the program window, where the user sees each edit and can undo it. This page is the technical reference (options, transports, the 74 tools, resources and the security model); how to connect a particular client is explained on the AI page.

5.1.1What it is#

  • A thin layer over the operations layer. Each tool is one operation of ogr_api (73 operations), plus server_info, which only the server has. The tools are written by hand, because a tool's description and parameter types are the whole interface a language model sees; a test keeps the two in step: every operation has a tool, every tool calls an operation and every tool parameter is a parameter of its operation. The same operations can be called from Python (Section 5.3).
  • The official SDK. The server is built on the MCP SDK for Python (mcp ≥ 2.1 and < 3, MIT licence), installed by the [mcp] extra. The desktop program does not need it.
  • Two transports. Standard input/output (the default) and streamable HTTP, with a bearer token and, for clients that reach it over the Internet, OAuth 2.1.
  • SI units everywhere (m, kN, kPa, kN/m³, degrees), x to the right and y up, whatever unit system the window displays.
  • Analyses are jobs. An analysis runs in a child process that can be cancelled; every edit of a model is one undo step.
  • The open window first. If OGR Slip2D is open, calls work on its window (Section 5.1.6).

5.1.2Installation#

From a clone of the repository, with Python 3.11 or later:

pip install -e ".[mcp]"
ogr-slip2d-mcp --version        # ogr-slip2d-mcp 0.1.235, on standard error
python -m ogr_mcp --version     # the same program, if the command is not on PATH

Without the SDK the server stops with exit code 3 and asks for the extra (pip install "ogr-slip2d[mcp]"). ogr-slip2d-mcp --help lists every option. Client configuration files, for desktop chat applications, local models and HTTP clients, are on the AI page.

5.1.3Command-line options#

Table 5.1.1 Options of ogr-slip2d-mcp.
OptionDefaultMeaning
--transport {stdio,http}stdioTransport (Section 5.1.4).
--host HOST127.0.0.1HTTP: interface to listen on. A host that is not a loopback address needs an explicit token.
--port PORT8765HTTP: port.
--token TOKEN—HTTP: bearer token. On the command line it is visible to other users of the machine: prefer --token-file or OGR_MCP_TOKEN.
--token-file FILE—HTTP: file holding the bearer token (UTF-8; surrounding white space is ignored).
--no-authoffHTTP on a loopback host only: no token. Since python_exec is always available, any local program can then run code as you. Refused with any other host and with --public-url.
--allow-origin ORIGIN—HTTP: one more allowed Origin; repeatable.
--public-url URL—HTTP: the https:// address the server is reached at from outside, through a tunnel or reverse proxy. Turns on OAuth 2.1; access is approved with the server's token. An http:// address is accepted only on a loopback host, for testing.
--oauth-redirect URI—With --public-url: one more allowed OAuth redirect URI; repeatable.
--tls-cert FILE—HTTP: serve HTTPS directly with this certificate (PEM). Goes with --tls-key.
--tls-key FILE—HTTP: the private key of --tls-cert (PEM).
--profile {full,compact}fullTool set (Section 5.1.5); also read from OGR_MCP_PROFILE.
--toolsets LIST—Comma-separated toolsets instead of a profile.
--attach [PID]—Work only on an open program window, never on a model of the server's own; with a process id, on that window.
--headlessoffNever use an open window: always work on the server's own models (the behaviour before v0.1.207).
--workdir DIR—Folder that relative paths are resolved against (opening and saving .ogr files, images, reports). Without it, paths must be absolute.
--max-wait SECONDS50Longest a tool waits for a job before returning its job_id.
--max-jobs N1Jobs allowed to run at the same time; one more is refused with E_BUSY.
--log-file FILEstandard errorWhere log messages go.
--version—Print the version on standard error and exit.
Table 5.1.2 Environment variables read by the server.
VariableMeaning
OGR_MCP_TOKENHTTP bearer token, used when neither --token nor --token-file is given.
OGR_MCP_PROFILEProfile, used when --profile is not given.
OGR_BRIDGE_DIRFolder where open windows announce their agent bridge (default ~/.ogr-slip2d/bridges). The program and the server must see the same value.
Table 5.1.3 Exit codes of ogr-slip2d-mcp.
CodeMeaning
0Normal end.
2A configuration the server refuses to run with: a non-loopback host without a token; --no-auth with a non-loopback host or with --public-url; an HTTP-only option (--public-url, --tls-cert, --tls-key, --oauth-redirect) with stdio; --oauth-redirect without --public-url; --tls-cert without --tls-key or a file that does not exist; a public URL that is not https://; a token shorter than 32 characters with --public-url; --attach together with --headless or with a process id that is not a number; an unknown profile or toolset.
3The MCP SDK is not installed.

Nothing is written on standard output, because over stdio that stream carries the protocol. Messages go to standard error, or to --log-file.

In OGR Slip2D

The options, the exposure rules and the exit codes are checked in one place before anything listens. The default --max-wait of 50 s is kept below the 60 s at which many clients cut a request.

Source: ogr_mcp/cli.py · ogr_mcp/server.py

5.1.4Transports#

Standard input/output#

The client starts the server as a child process and talks to it through its standard streams; no port is opened. This is the transport of desktop chat applications, coding agents and local-model clients.

ogr-slip2d-mcp --workdir "C:\models"
ogr-slip2d-mcp --profile compact --workdir "C:\models"     # small local models

Streamable HTTP#

With --transport http the server answers at http://HOST:PORT/mcp, stateless and with JSON responses. Every request needs Authorization: Bearer <token>; a missing or wrong token is answered 401. The token comes from --token, --token-file or OGR_MCP_TOKEN, in that order. When none is given on a loopback host, the server generates one (43 characters) and prints it on standard error when it starts.

ogr-slip2d-mcp --transport http --port 8765 --token-file token.txt --workdir "C:\models"

The Host and Origin headers are checked even when the token is right: a Host that is not this server's is answered 421 and a foreign Origin 403. Allowed hosts are 127.0.0.1, localhost, [::1] and --host, at the port; allowed origins are 127.0.0.1 and localhost at the port, plus each --allow-origin. With --tls-cert and --tls-key the same endpoint is served over HTTPS.

OAuth 2.1 for clients on the Internet#

Some hosted clients connect only to a public HTTPS server and only through OAuth. For them, the server keeps listening on 127.0.0.1, a tunnel or reverse proxy that terminates HTTPS is placed in front of it, and the server is told its public address with --public-url. It then acts as its own OAuth 2.1 authorization server: PKCE with S256, dynamic client registration and tokens bound to the resource <public-url>/mcp. Access is granted by typing the server's token on its page <public-url>/approve; whoever knows the token is taken to be the owner. The static token keeps working as a bearer header for clients that can send one. The limits are listed under Section 5.1.11.

ogr-slip2d-mcp --transport http --port 8765 --token-file token.txt \
               --public-url https://your-tunnel.example --workdir "C:\models"
Exposure

A server reachable from the Internet exposes python_exec, that is, the machine. Expose it only when a client needs it, and stop the tunnel and the server when finished. The server opens no tunnel by itself.

5.1.5Profiles and toolsets#

A small local model loses its way among many tools, and every tool's description costs context on every request. The server therefore offers two profiles:

  • full (default): all 74 tools.
  • compact: the 14 tools a complete build–run–read cycle needs: server_info, catalog, project_new, project_open, project_save, project_summary, model_define, analysis_configure, analysis_run, job_get, job_cancel, results_get, model_render and python_exec. model_define builds the whole geometry in one call and python_exec covers the rest. They are marked C in the tables of Section 5.1.7.

--toolsets replaces the profile by a list of toolsets: core (10 tools), model (9), settings (3), analysis (7), loads (5), supports (6), search (5), annotations (4), files (5), groundwater (11), statistics (6), view (1), history (1) and python (1). server_info is always included. Tools are published in a fixed order, so a client can cache the list.

ogr-slip2d-mcp --toolsets core,model,settings,analysis,view --workdir "C:\models"

5.1.6Working on the open program window#

Since v0.1.207 the program opens its agent bridge when it starts (Tools → Agent bridge (MCP), ticked by default). If OGR Slip2D is open, a call goes to its window; if it is not, to models of the server's own. The order in which the program and the client are opened does not matter, and a window that is closed and opened again is found again.

  • Which call goes where. A call that names a project_id, job_id or result_id the server holds stays with the server, so a model begun before the window was opened is not lost. Any other call goes to the window if one answers (the most recently started one when several are open) and otherwise to the server's own models. server_info says where the next call goes (attached_to_window: mode, whether a window is open, its process id and title, next_call_goes_to), and each entry of open_models says in_window.
  • It is the user's model. The user sees every edit; each edit of the agent is one step of Edit → Undo, and the user's own steps can be undone by the agent; the canvas is redrawn after each edit. An analysis the agent runs appears in the results panel and on the canvas, as a Compute would. model_render(source="window") returns a capture of the canvas as it is on screen.
  • Unsaved work is protected. project_new and project_open open in the window and refuse (E_CONFLICT) while it has unsaved changes: the agent has to save them with project_save or ask the user. project_close never closes the window's model.
  • Busy. While the window is computing (its own Compute or drawdown sweep, which use the live model on another thread), an edit answers E_BUSY, to be retried when the window has finished.
  • Relative paths are resolved against the server's --workdir, which the server sends to the window when it connects (the last server to connect sets it).
  • A window that closes mid-call. A call the window was answering when it closed is not repeated, because whether it ran cannot be known: it answers E_CONFLICT, and the model should be checked with project_summary before repeating it.
Table 5.1.4 How the server uses an open window.
ModeWindow openNo window open
defaultcalls go to the window (the most recent one)calls go to the server's own models
--attachcalls go to the windowcalls answer E_NOT_CONFIGURED, saying what to open
--attach PIDcalls go to the window of that processas --attach
--headlessthe window is never usedcalls go to the server's own models

The bridge listens only on 127.0.0.1, at a port chosen by the system, with a new random token each time it starts. The window announces both in ~/.ogr-slip2d/bridges/<pid>.json (port, token, process id and window title); on POSIX systems only the user can read that file. It is deleted when the bridge is switched off or the window closes, and a file whose port no longer answers is removed by the next server that looks. A connection whose first line does not carry the right token is answered E_UNAUTHORIZED and closed. To keep the bridge off, untick Tools → Agent bridge (MCP) or start the program with python -m ogr_gui --no-agent-bridge (Section 5.2).

In OGR Slip2D

The bridge carries the same operations as the headless server, as JSON lines (protocol ogr-slip2d-bridge/1), and runs them on the window's thread, so an edit of the agent and one of the user never race. The window's model is read at each call, so File → New and File → Open in the window are seen at once.

Source: ogr_api/bridge.py · ogr_gui/agent_bridge.py

5.1.7Tools#

The 74 tools of the full profile, grouped as in the program's own tool list. C marks the 14 tools of the compact profile. Hint is the MCP annotation the server declares for the tool (read-only, edit or destructive), which clients that ask for confirmation can use. The exact parameters and their descriptions are published by the server itself (tools/list).

Project (core)#

Table 5.1.5 Project tools.
ToolCHintWhat it does
server_infoCread-onlyVersion, units, modelling rules, open models and coverage of the program. The first call.
catalogCread-onlyWhat the program offers: strength models with their parameters, methods, searches, boundary types, settings with their options.
project_newCeditCreates an empty model or the demo slope; returns its project_id.
project_openCeditOpens a .ogr file.
project_saveCeditSaves to .ogr, the format the desktop program opens.
project_closedestructiveCloses a model; refuses to lose unsaved changes unless told to.
project_listread-onlyThe open models.
project_summaryCread-onlyThe model: boundaries, materials, which material occupies each region and how (assigned, inherited or the first by default), state, history and results.
project_validateread-onlyWhat an analysis would check, without computing.
project_getread-onlyOne section of the model as the .ogr file stores it (Section 5.4).

Model (model)#

Table 5.1.6 Model tools.
ToolCHintWhat it does
model_defineCeditThe whole model in one call: boundaries, materials, a point inside the region of each, water table and settings.
boundary_addeditOne boundary: external, material, water table, piezometric line, drawdown line, tension crack, Block Search object, weak layer or anisotropic surface (details below).
boundary_editdestructiveEdits or deletes a boundary: vertices, translation, type, name; op=block_object changes the kind of a Block Search object. It also copies, scales, rotates and simplifies.
material_seteditCreates or modifies a material, also its rapid-drawdown envelope (drawdown_envelope, since v0.1.200); hydraulic properties go through hydraulic_set. A range of a Generalized Anisotropic material takes a material of the model by name ("material": "Clay", since v0.1.228), and the analysis uses that material's strength as it is when it runs.
material_deletedestructiveDeletes a material; refused while regions, weak layers or ranges of a Generalized Anisotropic material use it, unless reassign_to or force is given.
material_assigneditAssigns a material to the region that contains a point.
external_reshapeeditExpands or shrinks the external boundary: a parallel offset, or a fill or excavation polyline with both ends on it.
slope_angle_changeeditChanges the overall angle of the slope face between two vertices of the external boundary (toe and crest). Only the face moves, projecting horizontally (default), vertically or by rotation; keep_benches keeps the width of the benches. Boundaries that end on the face follow it; supports and loads do not move, and a warning says so.
geometry_cleanupeditReports duplicate vertices, self-intersections and crossings between boundaries; with apply, corrects them.

boundary_add details. A closed material boundary (closed=true) is a lens: a region of its own and a hole in the region around it (since v0.1.197). A Block Search object carries its kind in block_object (since v0.1.232): window, line, point or polyline. A polyline gives each trial surface two points and the stretch of polyline between them, and accepts left_point and right_point (any, segment, end_point); two open points without a kind are a line, not a polyline. Since v0.1.233 an object also carries a group_id (an integer, 0 by default) that is read only with search.block_multiple_groups on: each group is then searched separately, the number of surfaces is shared among the groups, and polylines of different groups may overlap in x.

Loads (loads)#

Table 5.1.7 Load tools.
ToolCHintWhat it does
load_seteditAdds or changes a distributed load (kPa between two points) or a line load (kN/m at a point).
load_deletedestructiveDeletes loads.
seismic_seteditPseudo-static seismic load: khk_h, kvk_v and whether it applies. Both forces act on the static weight of the soil (loads and ponded water carry no seismic force); kvk_v is positive downwards (the soil weighs W(1+kv)W(1 + k_v)); kh≥0k_h \ge 0 is a magnitude that always acts in the direction of failure; and ∣k∣<1|k| < 1.
seismic_record_seteditAdds an acceleration record (file, text or values) for the Newmark analysis, or renames it.
seismic_record_deletedestructiveDeletes an acceleration record.

A line load normal to the boundary or at an angle to the boundary takes its direction from the ground surface at its point (since v0.1.199): the normal points into the ground (at a vertex, along the bisector), and the angle is measured anticlockwise from the ground surface traversed from left to right, so −90° is the normal. Off the ground surface such a load is refused.

Supports (supports)#

Table 5.1.8 Support tools.
ToolCHintWhat it does
support_type_seteditDefines or changes a support type (the set of properties of one class).
support_type_deletedestructiveDeletes a type; refused while supports use it.
support_seteditPlaces a support (head on the slope face, tail inside the ground), or moves, stretches or edits one.
support_pattern_addeditA row of supports along a segment.
support_deletedestructiveDeletes supports or a whole pattern.
support_ungroupeditUngroups a pattern.

Annotations (annotations)#

Table 5.1.10 Annotation tools.
ToolCHintWhat it does
annotation_seteditDraws lines, arrows, texts, dimensions, axes and images, or changes or hides them. The analysis never reads them.
annotation_deletedestructiveDeletes annotations.
annotation_to_boundaryeditThe only bridge, and an explicit one, from a drawing to the model.
properties_tableread-onlyTables of materials, supports or hydraulic properties.

Files (files)#

Table 5.1.11 File tools.
ToolCHintWhat it does
dxf_inspectread-onlyReads a DXF file without importing it: layers, proposed type, unit and problems.
dxf_importeditImports its geometry (one undo step).
dxf_exporteditExports the model and the critical surfaces of a result.
report_generateeditPDF report of an analysis.
properties_importeditCopies materials or support types from another .ogr file. A range of a Generalized Anisotropic material that took a material is linked to its imported copy or to the material of the same name; if there is neither, it keeps its strength without a link and a note says so.

Groundwater (groundwater, since v0.1.200)#

Table 5.1.12 Groundwater tools.
ToolCHintWhat it does
hydraulic_seteditHydraulic properties of a material: saturated permeability and anisotropy, model of the unsaturated zone (with its soil library), water contents and storage. A parameter of another model is refused.
mesh_generatedestructiveFinite-element mesh. It replaces the previous one and deletes its boundary conditions and fields, also those of the transient stages, because they are keyed by node number.
mesh_resetdestructiveRemoves the mesh and everything computed on it.
seepage_bc_seteditA boundary condition on a side (left, right, bottom, ground), at nodes, along a polyline of the boundary, or a reservoir at an elevation.
seepage_bc_cleardestructiveReturns to the default conditions (unknown on the ground surface, no flow elsewhere), which prescribe no head.
transient_seteditThe staged transient analysis: times, conditions of each stage, Calculate SF and initial state.
water_grid_seteditWater pressure grid (points or a CSV file) and its interpolation options.
water_grid_deletedestructiveRemoves the water pressure grid.
groundwater_runeditSolves the groundwater (steady state, or the transient stages with their factor of safety) in the background. The field is written back into the model as one undo step, unless the model has changed in the meantime.
groundwater_resultseditReads the field: summary, values at a point, flow through a section, free surface, stages with their factors, or every node as CSV. Also works after the project has been reopened.
drawdown_sweep_runeditRapid drawdown to several reservoir levels, because total drawdown is not always the worst case; through the same door as an analysis (design factors and checks).

Units: hydraulic heads in m and pore pressure in kPa; permeability, infiltration and nodal flow in one consistent unit (m/s). Since v0.1.200 each permeability model takes suction in the unit of its own definition: van Genuchten and Gardner in suction head (α in 1/m); Brooks–Corey, Fredlund–Xing, Simple and the user-defined curve in matric suction (kPa).

Statistics, back analysis and optimisation (statistics, since v0.1.201)#

Table 5.1.13 Statistics, back-analysis and optimisation tools.
ToolCHintWhat it does
random_variable_listread-onlyThe inputs of the model that can be random variables, with their key and value, and those already defined.
random_variable_seteditMakes an input random or changes it: distribution, standard deviation, range, correlation. The mean is always the model's value.
random_variable_deletedestructiveRemoves a variable; correlations that pointed to it are cleared.
statistics_runeditCompute Statistics in the background: the deterministic run, then the probabilistic analysis (probability of failure, reliability index) or the sensitivity analysis, with the design factors and the seed of the model.
back_analysis_runeditThe horizontal support force needed for a target factor of safety, over the configured search.
optimize_runeditOptimises the non-circular critical surface of a result with the model's settings and seed; the outcome is a new result.

The three runs go through the same door as analysis_run: without a design standard they give the same results as before; with one, they analyse the factored model.

Settings (settings)#

Table 5.1.14 Settings tools.
ToolCHintWhat it does
settings_getread-onlyEvery setting with its value, type and options.
settings_seteditAny setting by its path (search.search_method); all or nothing.
analysis_configureCeditThe most common analysis settings in one call: methods, surface type, search, slices, grid, failure direction, design standard.

Analysis (analysis)#

Table 5.1.15 Analysis tools.
ToolCHintWhat it does
analysis_runCeditStarts the analysis in the background; returns the result or a job_id.
job_getCread-onlyState and progress of a job; its result once it has finished.
job_cancelCdestructiveStops an analysis and every process it started.
job_listread-onlyThe jobs of the session.
results_getCread-onlyReads a result: summary, critical surface with its slices, best surfaces, minima, warnings.
results_queryeditWhat the Interpret window asks (since v0.1.201): error codes (−120 tensile, −112 m-alpha, −111 not converged, −101 other) and the census of rejected surfaces, raw data, surfaces through a point (measured on the surface that was computed, not on the whole circle), minimum per centre, factor along the slope, slices with the method's numbers, filters; and, of a statistics result, histogram, convergence, samples with their index and sensitivity.
surface_evaluateread-onlyThe factor of safety of one given surface (circle, three points or polyline), without a search.

View, history and Python (view, history, python)#

Table 5.1.16 View, history and Python tools.
ToolCHintWhat it does
model_renderCread-onlyPNG image of the model, with the critical surfaces of a result, or with contours of the groundwater field (field) and its free surface; with the program open, source="window" captures the canvas of the window.
project_historyeditUndoes, redoes or lists the edits.
python_execCdestructivePython against the model, for what has no tool yet (Section 5.1.11).
In OGR Slip2D

server_info also reports how much of the program an agent can reach (program_coverage): in v0.1.235, 116 of the 140 actions of the main window are mapped to an operation, none is pending, and the other 24 only make sense in the interface (zoom, pan, printing, preferences and the like), each with its reason written down.

Source: ogr_mcp/server.py · ogr_mcp/profiles.py · ogr_api/inventory.py · docs/mcp/herramientas.md

5.1.8Resources#

Table 5.1.17 Resources published by the server.
URITypeContent
ogr://guideMarkdownThe complete modelling guide the agent reads: units and axes, geometry, water, finite-element groundwater, statistics, materials, search and methods, running and reading results, undo and scripts, work on the window, files.
ogr://catalog/{kind}JSONcatalog(kind) as a resource. Kinds: strength_models, methods, search_methods, surface_types, boundary_types, pore_pressure_types, groundwater_methods, interslice_functions, failure_directions, unit_systems, design_standards, settings.

Many clients never read resources. A short version of the guide therefore travels with every connection as the server's instructions, and every rule that changes a number is in it and repeated in the tool descriptions where it applies.

5.1.9Modelling workflow#

project_new → model_define → project_validate → analysis_configure
            → analysis_run → results_get / model_render → project_save
  • Each call returns or takes a project_id; it may be omitted while only one model is open.
  • analysis_run runs every enabled method as a background job and waits up to wait_seconds (30 s by default, capped at --max-wait). If it answers state: "running" with a job_id, poll job_get (with a wait) until done; job_cancel kills the job's whole process tree. A job is queued, running, done, failed, cancelled or crashed.
  • A finished job carries a result_id: results_get(result_id, view=…) with summary, critical (with slices), top, minima or warnings, and model_render(result_id=…) draws its critical surfaces. The server keeps the last five results of each model.
  • Warnings are how the program reports a problem it has noticed, so they should be read before a result is relied on.

Rules that change the number#

The rules the server gives every agent, because each of them changes a factor of safety without an error:

  1. A region nobody assigned takes the first material of the list. The convention is silent: project_summary says for each region whether its material was assigned, inherited or the default_first_material.
  2. A water table or piezometric line does nothing until materials point at it (model_define water_table.materials, or boundary_add assign_to).
  3. The grid search nx and ny are intervals: points = nx + 1; radius_increment 10 means 11 radii per centre. Total circles = (nx + 1)(ny + 1)(radius_increment + 1).
  4. analysis_run may return state: "running" with a job_id: poll job_get.
  5. A result marked stale was computed on a model that has changed since.
  6. A finite-element groundwater field (groundwater_run) reaches only the materials whose pore_pressure is fem.

The full guide adds that, with a design standard on, the number reported is an over-design factor, which must exceed 1, not a factor of safety (results say which in caption); that failure_direction is left_to_right when the slope goes down to the right; and that the unit system in the settings only changes what the interface displays.

5.1.10Errors#

A tool that fails answers with a coded message, [E_CODE] message Hint: …; an unknown name comes with the closest known names (Did you mean …?). The codes are listed in Section 5.5.4. A setting that the analysis would not read is refused with the reason instead of being stored, and a failed or crashed job is reported as E_JOB_FAILED with its error.

5.1.11Security model#

python_exec: arbitrary code execution#

The server always publishes python_exec, which runs arbitrary Python in the server process with the permissions of the user who started it; through the bridge, it runs inside the program window's process. It is the owner's decision (2026-09-24), to cover whatever has no tool yet. As a result, whoever can talk to the server can run code on the machine, and everything below follows from that.

  • The script sees project (the live model), api (every operation: api.material_set(...)), np, ogr_core, ogr_slip2d and result(result_id); the value of its last expression is returned.
  • The whole script is one undo step, rolled back if it raises. Output is cut at 20 000 characters, and the returned value at 5 000.
  • A script cannot be stopped: one that never ends holds its model's lock until the process exits. That is why analyses are jobs and scripts are not.

Over stdio#

The server is a child process of the client and opens no port. The remaining risk is prompt injection: a text the model reads (a file, a web page) can ask it to run something. Clients that ask for confirmation before each tool are the defence; it should stay on for python_exec, which the server declares destructive.

Over HTTP#

  • A token always, also on 127.0.0.1. "Only local" is not a boundary: any web page can make the browser send requests to localhost. The token is compared in constant time.
  • Host and Origin are checked (the SDK's DNS-rebinding protection, switched on): 421 for a foreign Host, 403 for a foreign Origin, even with the token.
  • An explicit token off loopback. On a host that is not loopback the server requires an explicit token (--token, --token-file or OGR_MCP_TOKEN) and refuses to start without one (exit code 2). --no-auth is accepted only on loopback.
  • A token on the command line is visible to other users of the machine: --token-file or OGR_MCP_TOKEN are preferable.

The bridge to the window#

The bridge listens only on 127.0.0.1, with a new random token at each start, written to a file in the user's home folder. Whoever has the bridge drives the window, python_exec included. It opens no new access, because reading that file already requires being that user on that machine; it can still be switched off in Tools → Agent bridge (MCP) or with --no-agent-bridge. The program's tests run with an empty discovery folder of their own, so a test that starts a server cannot edit a model the user has open.

On the Internet (--public-url)#

  • The server opens no tunnel by itself; a tunnel or proxy that terminates HTTPS goes in front of it, or --tls-cert and --tls-key serve HTTPS directly.
  • Approval is granted by typing the server's token on /approve, a page that names the client asking and where it will be sent back, and warns that approving lets it run every tool, python_exec included. A wrong token is answered after a delay of one second; after 5 wrong tokens a request is locked; after 20 wrong tokens within 10 minutes, counting every request, all approvals stop for a while (anyone can open a new request, so a per-request limit alone would not bound the guessing).
  • For the same reason the token must have at least 32 characters with --public-url; a generated one has 43.
  • No other site can frame the approval page (X-Frame-Options: DENY, frame-ancestors 'none'), and neither the page nor where it came from is kept (no-store, no-referrer).
  • An approval yields an authorization code (PKCE S256, single use, valid for 5 minutes); a pending request expires after 10 minutes. Tokens issued are opaque and live in memory, so restarting the server revokes them all: access tokens last one hour, refresh tokens thirty days and are rotated at each use. Revocation is enabled; identity-assertion grants are refused.
  • The server's own token keeps working as Authorization: Bearer for clients that send headers.
  • Clients register dynamically (RFC 7591), and only with redirect URIs on an allowlist: the callback addresses of the hosted clients listed in ogr_mcp/oauth.py, loopback addresses, and those added with --oauth-redirect.
  • Client ID metadata documents are not offered: they would make the server fetch a document from another site, and the server makes no network calls.
  • --no-auth never goes with --public-url, and an http:// public URL is accepted only on loopback, for testing. The public Host and Origin join the allowed ones; any other still gets 421 or 403.

Files, network and telemetry#

  • Relative paths are resolved against --workdir. Saving never overwrites an existing file without overwrite=true, except the model's own file, which is what saving means.
  • The server makes no network call of its own. The opentelemetry-api dependency that the SDK brings is only the API: without a telemetry SDK configured, it exports nothing.
In OGR Slip2D

The security rules are written in the program's own documentation and enforced in the code listed here; this section follows them.

Source: docs/mcp/seguridad.md · ogr_mcp/security.py · ogr_mcp/oauth.py · ogr_api/pyexec.py
Engineering judgement

An agent can build and run a model quickly, and can also get it wrong quickly. Before relying on a number, check the geometry, the materials of each region and the pore pressures it set. The responsibility for a design stays with the engineer who signs it.