osm-edit-mcp 0.2.0__tar.gz
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.
- osm_edit_mcp-0.2.0/.gitignore +198 -0
- osm_edit_mcp-0.2.0/LICENSE +21 -0
- osm_edit_mcp-0.2.0/PKG-INFO +327 -0
- osm_edit_mcp-0.2.0/README.md +276 -0
- osm_edit_mcp-0.2.0/lhm.plugin.json +1482 -0
- osm_edit_mcp-0.2.0/oauth_auth.py +478 -0
- osm_edit_mcp-0.2.0/pyproject.toml +136 -0
- osm_edit_mcp-0.2.0/scripts/security_audit.py +410 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/__init__.py +13 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/_version.py +18 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/app.py +20 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/auth.py +97 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/config.py +332 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/edit_tools.py +258 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/http_client.py +67 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/natural_language.py +332 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/prompts.py +89 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/proposal_store.py +375 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/read_tools.py +1187 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/server.py +187 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/token_store.py +112 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/track_tools.py +2728 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/valhalla.py +161 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/write_tools.py +1104 -0
- osm_edit_mcp-0.2.0/src/osm_edit_mcp/xml_models.py +94 -0
- osm_edit_mcp-0.2.0/tests/__init__.py +1 -0
- osm_edit_mcp-0.2.0/tests/conftest.py +61 -0
- osm_edit_mcp-0.2.0/tests/test_auth_safety.py +155 -0
- osm_edit_mcp-0.2.0/tests/test_config.py +280 -0
- osm_edit_mcp-0.2.0/tests/test_edit_tools.py +85 -0
- osm_edit_mcp-0.2.0/tests/test_escaping.py +81 -0
- osm_edit_mcp-0.2.0/tests/test_lobehub_manifest.py +69 -0
- osm_edit_mcp-0.2.0/tests/test_module_boundaries.py +33 -0
- osm_edit_mcp-0.2.0/tests/test_oauth_flow.py +209 -0
- osm_edit_mcp-0.2.0/tests/test_package_metadata.py +55 -0
- osm_edit_mcp-0.2.0/tests/test_prompts.py +69 -0
- osm_edit_mcp-0.2.0/tests/test_proposal_store.py +88 -0
- osm_edit_mcp-0.2.0/tests/test_read_tools.py +141 -0
- osm_edit_mcp-0.2.0/tests/test_release_artifacts.py +74 -0
- osm_edit_mcp-0.2.0/tests/test_security_audit.py +31 -0
- osm_edit_mcp-0.2.0/tests/test_track_tools.py +1136 -0
- osm_edit_mcp-0.2.0/tests/test_valhalla.py +90 -0
- osm_edit_mcp-0.2.0/tests/test_way_writes.py +92 -0
- osm_edit_mcp-0.2.0/tests/test_xml_parser.py +124 -0
- osm_edit_mcp-0.2.0/web_server.py +330 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
pip-wheel-metadata/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
target/
|
|
76
|
+
|
|
77
|
+
# Jupyter Notebook
|
|
78
|
+
.ipynb_checkpoints
|
|
79
|
+
|
|
80
|
+
# IPython
|
|
81
|
+
profile_default/
|
|
82
|
+
ipython_config.py
|
|
83
|
+
|
|
84
|
+
# pyenv
|
|
85
|
+
.python-version
|
|
86
|
+
|
|
87
|
+
# pipenv
|
|
88
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
89
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
90
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
91
|
+
# install all needed dependencies.
|
|
92
|
+
#Pipfile.lock
|
|
93
|
+
|
|
94
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
95
|
+
__pypackages__/
|
|
96
|
+
|
|
97
|
+
# Celery stuff
|
|
98
|
+
celerybeat-schedule
|
|
99
|
+
celerybeat.pid
|
|
100
|
+
|
|
101
|
+
# SageMath parsed files
|
|
102
|
+
*.sage.py
|
|
103
|
+
|
|
104
|
+
# Environments
|
|
105
|
+
.env
|
|
106
|
+
.venv
|
|
107
|
+
env/
|
|
108
|
+
venv/
|
|
109
|
+
ENV/
|
|
110
|
+
env.bak/
|
|
111
|
+
venv.bak/
|
|
112
|
+
|
|
113
|
+
# Spyder project settings
|
|
114
|
+
.spyderproject
|
|
115
|
+
.spyproject
|
|
116
|
+
|
|
117
|
+
# Rope project settings
|
|
118
|
+
.ropeproject
|
|
119
|
+
|
|
120
|
+
# mkdocs documentation
|
|
121
|
+
/site
|
|
122
|
+
|
|
123
|
+
# mypy
|
|
124
|
+
.mypy_cache/
|
|
125
|
+
.dmypy.json
|
|
126
|
+
dmypy.json
|
|
127
|
+
|
|
128
|
+
# Pyre type checker
|
|
129
|
+
.pyre/
|
|
130
|
+
|
|
131
|
+
# OAuth credentials and tokens
|
|
132
|
+
oauth_tokens.json
|
|
133
|
+
.oauth_cache/
|
|
134
|
+
|
|
135
|
+
# Local development files
|
|
136
|
+
.env.local
|
|
137
|
+
.env.development
|
|
138
|
+
.env.production
|
|
139
|
+
.claude/settings.local.json
|
|
140
|
+
|
|
141
|
+
# IDE/Editor files
|
|
142
|
+
.vscode/
|
|
143
|
+
.idea/
|
|
144
|
+
*.swp
|
|
145
|
+
*.swo
|
|
146
|
+
*~
|
|
147
|
+
|
|
148
|
+
# macOS
|
|
149
|
+
.DS_Store
|
|
150
|
+
.AppleDouble
|
|
151
|
+
.LSOverride
|
|
152
|
+
|
|
153
|
+
# Windows
|
|
154
|
+
Thumbs.db
|
|
155
|
+
ehthumbs.db
|
|
156
|
+
Desktop.ini
|
|
157
|
+
|
|
158
|
+
# Log files
|
|
159
|
+
*.log
|
|
160
|
+
logs/
|
|
161
|
+
|
|
162
|
+
# Cache directories
|
|
163
|
+
.cache/
|
|
164
|
+
cache/
|
|
165
|
+
|
|
166
|
+
# Temporary files
|
|
167
|
+
tmp/
|
|
168
|
+
temp/
|
|
169
|
+
*.tmp
|
|
170
|
+
|
|
171
|
+
# Local GPX survey inputs can contain sensitive location history. Keep the
|
|
172
|
+
# directory available, but never commit its contents.
|
|
173
|
+
tracks/*
|
|
174
|
+
!tracks/.gitkeep
|
|
175
|
+
|
|
176
|
+
# Testing output
|
|
177
|
+
test-results/
|
|
178
|
+
.coverage.*
|
|
179
|
+
test_report.json
|
|
180
|
+
test_results.log
|
|
181
|
+
|
|
182
|
+
# OAuth tokens
|
|
183
|
+
.osm_token_dev.json
|
|
184
|
+
.osm_token_prod.json
|
|
185
|
+
.osm_token_*.json
|
|
186
|
+
|
|
187
|
+
# Security and keys
|
|
188
|
+
*.key
|
|
189
|
+
*.pem
|
|
190
|
+
*.p12
|
|
191
|
+
*.pfx
|
|
192
|
+
*.crt
|
|
193
|
+
*.cer
|
|
194
|
+
private_key*
|
|
195
|
+
secret_key*
|
|
196
|
+
|
|
197
|
+
# Security audit reports
|
|
198
|
+
security_audit_report.json
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 pk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: osm-edit-mcp
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Review-first MCP server for previewed, version-checked OpenStreetMap road edits from local GPX surveys
|
|
5
|
+
Project-URL: Homepage, https://github.com/skywinder/osm-edit-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/skywinder/osm-edit-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/skywinder/osm-edit-mcp/issues
|
|
8
|
+
Author: skywinder
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ai,assistant,fastmcp,geospatial,gis,gpx,map-editing,mcp,model-context-protocol,openstreetmap,osm
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: anyio<5,>=4.9.0
|
|
23
|
+
Requires-Dist: authlib<2,>=1.8.0
|
|
24
|
+
Requires-Dist: cryptography<51,>=50.0.1
|
|
25
|
+
Requires-Dist: defusedxml<1,>=0.7.1
|
|
26
|
+
Requires-Dist: fastapi<1,>=0.141.1
|
|
27
|
+
Requires-Dist: httpx<1,>=0.28.1
|
|
28
|
+
Requires-Dist: keyring<26,>=25.7.0
|
|
29
|
+
Requires-Dist: mcp<2,>=1.10
|
|
30
|
+
Requires-Dist: pydantic-settings<3,>=2.10.0
|
|
31
|
+
Requires-Dist: pydantic<3,>=2.11.0
|
|
32
|
+
Requires-Dist: python-dotenv<2,>=1.2.3
|
|
33
|
+
Requires-Dist: python-multipart<1,>=0.0.32
|
|
34
|
+
Requires-Dist: uvicorn[standard]<1,>=0.52.4
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: bandit[toml]>=1.8.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: flake8>=6.0.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: hatchling<2,>=1.27; extra == 'dev'
|
|
40
|
+
Requires-Dist: isort>=5.0.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
42
|
+
Requires-Dist: pip-audit>=2.9.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
47
|
+
Requires-Dist: tomli>=2.0.0; (python_version < '3.11') and extra == 'dev'
|
|
48
|
+
Requires-Dist: twine>=6.0.0; extra == 'dev'
|
|
49
|
+
Requires-Dist: types-defusedxml>=0.7.0.20260504; extra == 'dev'
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
|
|
52
|
+
# OSM Edit MCP
|
|
53
|
+
|
|
54
|
+
[](https://lobehub.com/mcp/pk-osm-edit-mcp)
|
|
55
|
+
|
|
56
|
+
A review-first Model Context Protocol server for inspecting OpenStreetMap and
|
|
57
|
+
turning a selected part of a local GPX survey into a previewed road-edit proposal.
|
|
58
|
+
|
|
59
|
+
> **Alpha software.** It does not autonomously edit OpenStreetMap. The normal
|
|
60
|
+
> profile can inspect data and prepare proposals, but a production write requires
|
|
61
|
+
> an exact preview, a separate MCP host confirmation of its SHA-256 digest, fresh
|
|
62
|
+
> OSM identity/version checks, and one atomic `osmChange` upload.
|
|
63
|
+
|
|
64
|
+
## Why this server
|
|
65
|
+
|
|
66
|
+
Most OpenStreetMap MCP servers focus on search, geocoding, or routing. OSM Edit
|
|
67
|
+
MCP focuses on the risky last mile: helping a mapper review a narrowly selected
|
|
68
|
+
survey before any road geometry reaches OSM.
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
local GPX → selected segment → current/proposed preview
|
|
72
|
+
→ exact digest confirmation → OSM changeset
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The safe profile can:
|
|
76
|
+
|
|
77
|
+
- read OSM nodes, ways, relations, changesets, and small map areas;
|
|
78
|
+
- analyze GPX 1.0/1.1 locally without publishing the trace;
|
|
79
|
+
- select one continuous range by index, time, or endpoint coordinates;
|
|
80
|
+
- optionally compare it with local Valhalla map matching;
|
|
81
|
+
- suggest nearby `highway=*` ways without choosing one automatically;
|
|
82
|
+
- preview a new road or a selected contiguous chain of existing ways;
|
|
83
|
+
- expose current/proposed GeoJSON through an MCP `ui://` resource;
|
|
84
|
+
- apply one confirmed proposal atomically and return OSM links and versions;
|
|
85
|
+
- re-fetch a completed edit for later verification.
|
|
86
|
+
|
|
87
|
+
It does **not** upload GPS traces, infer crossings, delete roads, restructure
|
|
88
|
+
relations, copy geometry from restricted providers, or authorize a production
|
|
89
|
+
edit from natural-language consent alone.
|
|
90
|
+
|
|
91
|
+
## Quick start
|
|
92
|
+
|
|
93
|
+
Requirements:
|
|
94
|
+
|
|
95
|
+
- Python 3.10 or newer;
|
|
96
|
+
- [uv](https://docs.astral.sh/uv/);
|
|
97
|
+
- an MCP host that supports local stdio servers.
|
|
98
|
+
|
|
99
|
+
Add this server to a JSON-based MCP host:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"mcpServers": {
|
|
104
|
+
"osm-edit": {
|
|
105
|
+
"command": "uvx",
|
|
106
|
+
"args": ["osm-edit-mcp"],
|
|
107
|
+
"env": {
|
|
108
|
+
"OSM_USE_DEV_API": "true",
|
|
109
|
+
"OSM_WRITE_PROFILE": "safe"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Restart the host, then call `get_server_info` or `get_edit_capabilities`.
|
|
117
|
+
The first `uvx` launch installs the released package in an isolated environment.
|
|
118
|
+
The development API is the default in this example; no OAuth credentials are
|
|
119
|
+
needed for read-only inspection.
|
|
120
|
+
|
|
121
|
+
For client-specific formats, including Codex TOML, see
|
|
122
|
+
[MCP client setup](docs/MCP_CLIENT_SETUP.md). A real read-only protocol smoke
|
|
123
|
+
client is available at [examples/quick_start.py](examples/quick_start.py).
|
|
124
|
+
|
|
125
|
+
MCP hosts can also start the guided `review_gpx_road_edit` prompt with a local
|
|
126
|
+
GPX path and edit goal. It requires explicit segment and target choices, builds
|
|
127
|
+
a non-writing preview, and stops at review of the complete proposal digest. It
|
|
128
|
+
never calls `apply_osm_edit`.
|
|
129
|
+
|
|
130
|
+
## Review workflow
|
|
131
|
+
|
|
132
|
+
Keep private tracks outside the repository. Set `OSM_TRACK_IMPORT_DIR` to a
|
|
133
|
+
directory you control, or provide inline GPX XML. Files are limited to 10 MiB
|
|
134
|
+
and 100,000 raw points; path traversal and symlink escapes are rejected.
|
|
135
|
+
|
|
136
|
+
### 1. Analyze the track
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
analyze_gpx_track(gpx_path="survey.gpx")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The result identifies stable track/segment IDs, bounds, distance, timestamps,
|
|
143
|
+
and discontinuities. Separate GPX segments are never joined implicitly.
|
|
144
|
+
|
|
145
|
+
### 2. Select only the surveyed section
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
create_track_selection(
|
|
149
|
+
track_id="<track_id>",
|
|
150
|
+
segment_id="trk-0-seg-0",
|
|
151
|
+
start_point_index=1240,
|
|
152
|
+
end_point_index=1395
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Timestamp and endpoint-coordinate selection are also supported. Review the
|
|
157
|
+
returned `preview_uri` or its GeoJSON fallback.
|
|
158
|
+
|
|
159
|
+
### 3. Compare with current OSM
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
match_track_selection(selection_id="<selection_id>", costing="auto")
|
|
163
|
+
suggest_track_road_candidates(selection_id="<selection_id>")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Valhalla output is diagnostic only. Candidate discovery never selects the target
|
|
167
|
+
way on the mapper's behalf.
|
|
168
|
+
|
|
169
|
+
### 4. Build a non-writing preview
|
|
170
|
+
|
|
171
|
+
Track analysis, segment selection, and the selection preview work without OAuth.
|
|
172
|
+
`preview_track_road_edit` still requires an authenticated OSM identity because
|
|
173
|
+
the proposal is bound to that exact account and API target, even though this
|
|
174
|
+
step does not write to OSM.
|
|
175
|
+
|
|
176
|
+
For a new road:
|
|
177
|
+
|
|
178
|
+
```text
|
|
179
|
+
preview_track_road_edit(
|
|
180
|
+
selection_id="<selection_id>",
|
|
181
|
+
action="create",
|
|
182
|
+
tags={"highway":"residential"},
|
|
183
|
+
changeset_comment="Add surveyed residential road",
|
|
184
|
+
changeset_source="survey",
|
|
185
|
+
evidence_kind="survey_gpx"
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
For an existing contiguous chain:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
preview_track_road_edit(
|
|
193
|
+
selection_id="<selection_id>",
|
|
194
|
+
action="update",
|
|
195
|
+
target_way_ids=[123456, 123457],
|
|
196
|
+
changeset_comment="Realign road from local survey",
|
|
197
|
+
changeset_source="survey",
|
|
198
|
+
evidence_kind="survey_gpx"
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Review the current/proposed GeoJSON, exact operations and tags, preserved nodes,
|
|
203
|
+
endpoint connections, warnings, blocking issues, API target, expiry, and
|
|
204
|
+
`proposal_digest`. Ambiguous topology is reported rather than invented.
|
|
205
|
+
|
|
206
|
+
### 5. Confirm and apply
|
|
207
|
+
|
|
208
|
+
`apply_osm_edit` accepts the exact proposal ID and digest. In production, the
|
|
209
|
+
MCP host must display a separate elicitation request for that digest. Apply then
|
|
210
|
+
checks the live OSM account, `write_api` permission, referenced versions, and
|
|
211
|
+
affected highways before sending one transactional upload.
|
|
212
|
+
|
|
213
|
+
A network failure after an upload starts becomes `RECONCILE_REQUIRED`; the
|
|
214
|
+
server does not blindly retry an ambiguous write.
|
|
215
|
+
|
|
216
|
+
### 6. Verify
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
verify_osm_edit(proposal_id="<proposal_id>")
|
|
220
|
+
list_edit_proposals(status="APPLIED")
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Safety model
|
|
224
|
+
|
|
225
|
+
The normal `safe` profile enforces:
|
|
226
|
+
|
|
227
|
+
1. Exact, expiring proposals stored in a local SQLite state machine.
|
|
228
|
+
2. Atomic proposal claims that block concurrent or repeated upload.
|
|
229
|
+
3. API-target, account, permission, OSM-version, and content binding.
|
|
230
|
+
4. MCP elicitation bound to the proposal SHA-256 for production.
|
|
231
|
+
5. One transactional `osmChange` upload for creates and modifications.
|
|
232
|
+
6. Durable receipts and explicit reconciliation after ambiguous failures.
|
|
233
|
+
7. No registration of raw direct-write or natural-language write tools.
|
|
234
|
+
|
|
235
|
+
Raw write tools are available only in the explicit `expert` profile while
|
|
236
|
+
targeting the OSM development API.
|
|
237
|
+
|
|
238
|
+
GPX accuracy is not ground truth. Review every proposal against independent,
|
|
239
|
+
permitted evidence and local knowledge. Follow OpenStreetMap's mapping,
|
|
240
|
+
licensing, import, and automated-edit policies; systematic edits may require
|
|
241
|
+
community discussion even when this software requires per-proposal review.
|
|
242
|
+
|
|
243
|
+
## OAuth and production use
|
|
244
|
+
|
|
245
|
+
The package quick start is intentionally safe for inspection. Production setup
|
|
246
|
+
is an advanced operator workflow:
|
|
247
|
+
|
|
248
|
+
1. Register separate development and production OAuth applications with only
|
|
249
|
+
`read_prefs` and `write_api`.
|
|
250
|
+
2. From an existing source checkout, create a private `.env`, configure the
|
|
251
|
+
development application, then authenticate it:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
install -m 600 .env.example .env
|
|
255
|
+
uv sync --locked --extra dev
|
|
256
|
+
export OSM_EDIT_MCP_ENV_FILE="$PWD/.env"
|
|
257
|
+
uv run python oauth_auth.py --dev
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
3. Complete representative create/update preview and apply acceptance against
|
|
261
|
+
the OSM development API.
|
|
262
|
+
4. Only after that development acceptance, configure and authenticate the
|
|
263
|
+
separate production app:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
export OSM_EDIT_MCP_ENV_FILE="$PWD/.env"
|
|
267
|
+
uv run python oauth_auth.py --prod
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Tokens are keyring-first. Plaintext compatibility files are disabled by default
|
|
271
|
+
and, when explicitly enabled, must have mode `0600`.
|
|
272
|
+
|
|
273
|
+
Do not switch to `OSM_USE_DEV_API=false` unless
|
|
274
|
+
`get_edit_capabilities` reports the expected account, production target,
|
|
275
|
+
`safe` profile, and digest-bound host confirmation.
|
|
276
|
+
|
|
277
|
+
## Main tools
|
|
278
|
+
|
|
279
|
+
Inspection:
|
|
280
|
+
|
|
281
|
+
- `get_server_info`
|
|
282
|
+
- `get_edit_capabilities`
|
|
283
|
+
- `inspect_map_context`
|
|
284
|
+
- read/search/validation tools for OSM elements and tags
|
|
285
|
+
|
|
286
|
+
Review and editing:
|
|
287
|
+
|
|
288
|
+
- `analyze_gpx_track`
|
|
289
|
+
- `create_track_selection`
|
|
290
|
+
- `match_track_selection`
|
|
291
|
+
- `suggest_track_road_candidates`
|
|
292
|
+
- `preview_track_road_edit`
|
|
293
|
+
- `apply_osm_edit`
|
|
294
|
+
- `list_edit_proposals`
|
|
295
|
+
- `verify_osm_edit`
|
|
296
|
+
|
|
297
|
+
Guided prompt:
|
|
298
|
+
|
|
299
|
+
- `review_gpx_road_edit(gpx_path, edit_goal)`
|
|
300
|
+
|
|
301
|
+
## Development
|
|
302
|
+
|
|
303
|
+
From an existing source checkout:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
uv sync --locked --extra dev
|
|
307
|
+
uv run --locked --extra dev pytest
|
|
308
|
+
uv run --locked --extra dev pytest --cov=src/osm_edit_mcp --cov-report=term-missing
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Unit tests mock the network and force the development API at import time.
|
|
312
|
+
Development-API acceptance is separate and opt-in; it must never point at
|
|
313
|
+
production.
|
|
314
|
+
|
|
315
|
+
More documentation:
|
|
316
|
+
|
|
317
|
+
- [Quick start](docs/quick-start-guide.md)
|
|
318
|
+
- [MCP client setup](docs/MCP_CLIENT_SETUP.md)
|
|
319
|
+
- [Safe usage examples](docs/mcp-usage-examples.md)
|
|
320
|
+
- [Troubleshooting](docs/MCP_TROUBLESHOOTING.md)
|
|
321
|
+
- [Security policy](SECURITY.md)
|
|
322
|
+
- [Contributing](CONTRIBUTING.md)
|
|
323
|
+
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
MIT. OpenStreetMap edits are also subject to the OSM contributor terms,
|
|
327
|
+
community guidelines, and source-licensing requirements.
|