server_info
Server status: PostgreSQL/PostGIS versions, mode (read-only), limits, allowlists. Call once if unsure what is available.
无需输入参数。

io.github.mveyseldelibas由 GitHub 账号 mveyseldelibas 发布v0.2.0更新于 Nov 6, 2026
Safe MCP server for PostGIS and Oracle Spatial: query geodata and answer with maps.
面向 PostGIS 或 Oracle Spatial 的只读 MCP 服务器,让助手发现空间图层、执行空间查询并以地图形式返回结果。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
参照 仓库 中的启动说明。
Ask your PostGIS or Oracle Spatial database questions in plain English and get the answer back as a map.
mapsql-mcp is a Model Context Protocol server that lets AI assistants
(Claude Desktop, Claude Code, Cursor, and any other MCP client) explore, query and analyse a PostGIS or an
Oracle Spatial (SDO_GEOMETRY) database safely and answer with maps rendered right in the chat.
[License: MIT] [Python] [MCP] [status] [PostGIS] [Oracle Spatial]
[Pharmacies within 500 m of Kizilay]
"Which pharmacies are within 500 m of Kızılay square?" - the model discovers the layers, calls
within_distance(geodesic metres, whatever the table's SRID), thenrender_map. The picture above is the literal output of those two tool calls on the bundled demo database.
[mapsql-mcp demo: question, tool calls, map]
The GIF is built by scripts/make_demo_video.py from real tool outputs on the demo databases (PostGIS and Oracle).
Türkçe: kullanım kılavuzu aşağıda · Who is it for / step-by-step: Usage
Generic Postgres or Oracle MCP servers are not spatial-aware: the model has to hand-write PostGIS / SDO_* SQL and gets
SRIDs, geography casts, units and ST_DWithin / SDO_WITHIN_DISTANCE arguments wrong in subtle ways, then cannot show
the result. mapsql-mcp is built
around three ideas:
sqlglot in
Oracle mode), runs in a READ ONLY transaction with a timeout and a row cap, and secrets never reach the model. Writes
are off unless you ask for them (PostGIS only).within_distance, nearest, buffer, spatial_filter, spatial_join,
aggregate, bbox_of ... take care of SRIDs, metric units and indexes - the same 14 tools on both databases. Plain
run_sql is still there.render_map returns a PNG (OpenStreetMap basemap, choropleths, labels) as MCP image
content and can also write an interactive Leaflet HTML file.And the model is told to ask instead of guess: the server instructions, a prompt and the tools themselves refuse to proceed on "pharmacies nearby" (nearby what?) or on a place name that matches ten features.
Requires Python 3.10+ and a PostGIS or Oracle Spatial database. Use a read-only database role / user (see SECURITY.md). The backend is chosen from the connection string.
Edit claude_desktop_config.json (macOS ~/Library/Application Support/Claude/, Windows %APPDATA%\Claude\):
.cursor/mcp.json) / Windsurf.vscode/mcp.json, Copilot Chat in Agent mode)VS Code uses a servers key and can prompt for the password instead of storing it in the file:
Run the streamable-HTTP transport and point the client at http://127.0.0.1:8000/mcp:
There is no authentication on the HTTP transport: keep it on loopback or put it behind your own authenticating
reverse proxy / tunnel. If you installed from a clone use "command": "python", "args": ["-m", "mapsql_mcp"].
Who it is for. GIS developers, database people, analysts and researchers who already use an AI assistant (Claude Code, Claude Desktop, Cursor, VS Code + Copilot) and have spatial data in PostGIS or Oracle Spatial. It is a building block for an assistant, not an end-user app: there is no web UI of its own, the chat window is the UI.
1. Install:
2. Point it at a database with a read-only user and check the connection:
No database at hand? Build the bundled demo (Natural Earth + OpenStreetMap Ankara) in two minutes, see the next section.
3. Register it with your assistant. Put one of the JSON blocks from Quickstart into the client's config
(.mcp.json for Claude Code, .vscode/mcp.json for VS Code, .cursor/mcp.json for Cursor, claude_desktop_config.json
for Claude Desktop). In VS Code click Start above the server entry; in Claude Code run /mcp and check it says
connected. You should see 14 tools.
4. Ask in plain language. For example:
5. See the map. render_map returns the PNG to the assistant and saves it (and optionally an interactive Leaflet HTML)
under ~/mapsql-mcp-output. Some clients (e.g. the Claude Code panel in VS Code) do not show tool images to you; add
MAPSQL_OPEN_MAPS=1 (or --open-maps) to the server's env and every map opens in your default viewer.
Good to know. The assistant's provider (Anthropic, OpenAI, ...) receives the rows the tools return, so do not connect
databases whose content must not leave your organisation; use --schemas / --layers to expose only what is needed, and
keep the database user read-only.
The demo data is Natural Earth (world countries, provinces, cities, rivers, lakes - public domain) plus an OpenStreetMap
extract of central Ankara (POIs, roads, parks, 105 neighbourhoods - ODbL). A pinned snapshot ships in demo/data (2.8 MB),
so building it works offline.
Then ask your assistant, for example:
Map data © OpenStreetMap contributors (ODbL). Interactive versions of two of them: docs/images/*.html (open in a browser).
New in v0.2: the same tools, the same safety model and the same maps on Oracle Database with Spatial (19c, 21c, 23ai /
26ai, Autonomous Database, ...), through python-oracledb in thin mode (no Oracle Client libraries needed).
[Pharmacies within 500 m of Kizilay, Oracle Spatial]
Same question, same answer (20 pharmacies) as on PostGIS - this time from SDO_WITHIN_DISTANCE(... 'distance=500 unit=M')
on an Autonomous Database. Map data (c) OpenStreetMap contributors (ODbL).
All other settings (MAPSQL_SCHEMAS, MAPSQL_LAYERS, MAPSQL_STATEMENT_TIMEOUT_MS, MAPSQL_MAX_ROWS, ...) work unchanged;
the timeout is applied as the connection call_timeout, schemas are Oracle owners.
Autonomous Database (TLS, no wallet). In the console open Database connection, choose TLS authentication: TLS (instead
of mTLS; requires an access control list / allowed IPs for your address) and copy the Low/Medium connection string. The
descriptor looks like (description=(address=(protocol=tcps)(port=1522)(host=...))(connect_data=(service_name=...))(security=(ssl_server_dn_match=yes)));
put it in MAPSQL_ORACLE_DSN (it is long and contains parentheses, so it does not fit well in a URL). The server certificate is
verified against the operating system's trust store. Use a dedicated read-only user, never ADMIN.
scripts/oracle_readonly_user.sql is the Oracle counterpart of readonly_role.sql: a user with
only CREATE SESSION plus SELECT on the tables the assistant may see. The spatial metadata views, MDSYS.CS_SRS and the
SDO_* operators are available to every user, so nothing else is needed.
VS Code (.vscode/mcp.json) - the password is prompted for and never stored in the file; a TNS descriptor goes into MAPSQL_ORACLE_DSN:
scripts/oracle_demo_db.py loads the same Natural Earth + OpenStreetMap-Ankara data as the PostGIS demo into the schema
MAPSQL_DEMO (WORLD_COUNTRIES, WORLD_CITIES, ANKARA_POIS, ANKARA_NEIGHBOURHOODS, ... - Oracle has no schemas-within-a-database
convention like world.countries, so the PostGIS schema becomes a table-name prefix), registers USER_SDO_GEOM_METADATA, builds spatial indexes,
adds TUREF TM30 (EPSG:5254, metres) copies of two Ankara layers to exercise projected coordinate systems, and creates the
read-only user MAPSQL_RO. It needs an administrator login in a git-ignored ini file:
Metres are right on geodetic layers (EPSG:4326 and Oracle's legacy 8307: geodesic on the ellipsoid) and projected layers
(planar in the projection, converted with unit=M). Values are always bind variables; identifiers come from the catalog.
SDO_* operators. Layers without a valid spatial index are queried with index-free SDO_GEOM.*
functions (flagged in the response, and describe_layer warns). Create indexes (CREATE INDEX ... INDEXTYPE IS MDSYS.SPATIAL_INDEX_V2) and
register the layer in USER_SDO_GEOM_METADATA for speed.crosses has no faithful Oracle mask: spatial_filter refuses it with an explanation instead of returning a possibly wrong
answer (use intersects/touches/overlaps, or run_sql with your own SDO_RELATE mask). within/contains include boundary
contact (COVEREDBY/COVERS) and EQUAL; overlaps is OVERLAPBDYDISJOINT+OVERLAPBDYINTERSECT.--allow-write is refused at start-up).mapsql_demo.ankara_pois, column name) when they are plain upper-case Oracle names;
they remain valid unquoted in SQL. Quoted mixed-case names are shown as they are and must be quoted in run_sql.NULL. EQ '' filters are translated to IS NULL.dwithin joins on polygons can differ by a feature at the boundary; a buffer's area differs by its polygon approximation.
On a projected layer distances are planar in that projection (TM30 is within about 1 m per kilometre of geodesic distances near the central meridian).list_layers reports extents with SDO_AGGR_MBR (skipped for layers over 500 000 rows); SDO_TUNE.EXTENT_OF cannot run inside a READ ONLY transaction.All coordinates are WGS84 lon/lat; distances are metres; areas km². Every geometry-returning tool stores the full
(simplified) result server-side and returns a result_id, so render_map(result_ids=[...]) never needs the model to copy
big GeoJSON around. Responses stay small: geometries above a vertex budget are returned as representative points
(with a note) unless you ask for geometry="full".
Prompts: gis_assistant, spatial_question, explore_database. Resources: mapsql://guide, mapsql://layers.
within_distance with no point and no reference feature does not guess a location; it fails with
"Missing reference: near WHAT? ... ask them". A reference that matches several features returns the candidates and asks
which one is meant. Likewise a missing distance, an ambiguous layer name, a numeric filter given text, swapped lon/lat ...
The server instructions (sent on connect) tell the model to ask one short clarifying question first. This was motivated by
the author's TR-CBS-Komut benchmark, where models differed from 0% to 98% in recognising missing information.
Defence in depth - no single layer is trusted (SECURITY.md has the full threat model):
Basemap tiles come from tile.openstreetmap.org with attribution, a descriptive User-Agent, a ≤ 16-tile cap per map and
an on-disk cache. Please respect the OSM tile usage policy; for
heavy use point MAPSQL_BASEMAP at your own tile server, or use none (works fully offline).
bench/ ships 60 English GIS questions over the demo database (52 answerable + 8 that must be
answered with a clarifying question), in 8 categories (attribute, distance, spatial, aggregate, join, buffer, bbox,
ambiguous), with gold answers computed by hand-written SQL, and a runner that evaluates any OpenAI-compatible model
(OpenAI, OpenRouter, vLLM, Ollama, LM Studio ...) in an agent loop that calls this server's tools over stdio:
Scoring: numbers within a tolerance, names as case/accent-insensitive sets, and for ambiguous questions the model must
end with CLARIFY: instead of ANSWER:. What is verified today (v0.1): the gold answers match the database (52/52) and the
toolset can express every answerable question (oracle 52/52). No LLM results are published yet - the harness is
ready; PRs adding model results to bench/RESULTS.md are very welcome.
geometry/geography columns (PostGIS) or SDO_GEOMETRY columns (Oracle) of tables, views, materialised views, foreign tables. Oracle specifics: see Differences from PostGIS (read-only only, no crosses, index-free fallback).run_sql can still query them).render_map draws one flat colour per layer, plus a single-variable choropleth; no custom styling yet.execute_sql is a deliberately small write surface.dwithin joins can be slow.mcp 1.30 and 2.3 (the code supports both SDK generations); CI runs PostGIS 3.4 / PostgreSQL 16 and the Oracle guard tests (the database-backed Oracle tests skip without credentials).SDO_JOIN/Spatial Studio extras, auth for HTTP (bearer tokens), per-tool allowlists, vector-tile/PMTiles basemaps, raster/H3 summaries, an explain
tool, routing helpers (pgRouting), result export (GeoJSON/GeoPackage), richer map stylingOracle tests (pytest -m oracle) run when oracle-test.ini ([oracle_ro], see above) or MAPSQL_TEST_ORACLE_URL /
MAPSQL_TEST_ORACLE_DSN+_USER+_PASSWORD is available and scripts/oracle_demo_db.py has been run; otherwise they are skipped. The
Oracle SQL guard tests need no database.
See CONTRIBUTING.md. Windows helper for a local cluster: scripts/dev_cluster.ps1.
mapsql-mcp, yapay zekâ asistanlarının (Claude Desktop/Code, Cursor, ChatGPT uyumlu MCP istemcileri) bir PostGIS veya Oracle Spatial (v0.2) veritabanını güvenli biçimde sorgulamasını, mekânsal analiz yapmasını ve cevabı harita olarak sohbette göstermesini sağlayan açık kaynaklı bir MCP sunucusudur.
pglast) ile doğrulanır; tek SELECT, READ ONLY işlem,
zaman aşımı ve satır sınırı. pg_read_file, COPY, dblink, lo_* vb. engellidir. Yazma varsayılan olarak kapalıdır
(--allow-write). Şema/katman izin listesi (--schemas, --layers) desteklenir; parola ve bağlantı dizesi çıktıya sızmaz.list_layers, describe_layer, within_distance (metre cinsinden, SRID'den bağımsız), nearest,
buffer, spatial_filter, aggregate, spatial_join, bbox_of, run_sql ve render_map (OSM altlıklı PNG +
isteğe bağlı etkileşimli Leaflet HTML, kloropet harita).bench/ altında demo veritabanı üzerinde 60 İngilizce CBS sorusu (8'i "sormalı" tipi), altın cevaplar ve
herhangi bir OpenAI uyumlu modeli deneyen çalıştırıcı bulunur.Oracle Spatial: pip install "mapsql-mcp[oracle]" ve DATABASE_URL=oracle://KULLANICI:SIFRE@sunucu:1521/servis_adi
(uzun TNS tanımlayıcıları için MAPSQL_ORACLE_DSN + MAPSQL_ORACLE_USER + MAPSQL_ORACLE_PASSWORD). Aynı 14 araç; mesafeler
unit=M ile metre cinsinden, coğrafi (4326) ve projeksiyonlu (ör. TUREF TM30, EPSG:5254) katmanlarda doğrudur. Sorgular sqlglot
(Oracle lehçesi) ile doğrulanır, SET TRANSACTION READ ONLY ve salt okunur kullanıcı (scripts/oracle_readonly_user.sql) önerilir.
Ayrıntı: yukarıdaki Oracle Spatial bölümü.
Kimin için? Yapay zekâ asistanı (Claude Code, Claude Desktop, Cursor, VS Code + Copilot) kullanan ve mekânsal verisi PostGIS ya da Oracle Spatial'da duran CBS geliştiricileri, veritabanı uzmanları, analistler ve araştırmacılar için. Son kullanıcı uygulaması değildir; kendi ekranı yoktur, arayüzü sohbet penceresinin kendisidir.
1. Kurulum:
2. Veritabanını salt okunur bir kullanıcıyla bağlayın ve bağlantıyı deneyin:
Salt okunur kullanıcı betikleri: scripts/readonly_role.sql (PostGIS), scripts/oracle_readonly_user.sql (Oracle).
Elinizde veritabanı yoksa yukarıdaki Try it with the demo database bölümüyle iki dakikada demo veritabanı kurulur
(Natural Earth + OpenStreetMap Ankara).
3. Asistana tanıtın. Quickstart bölümündeki JSON örneklerinden birini istemcinin ayar dosyasına koyun: Claude Code
için .mcp.json, VS Code için .vscode/mcp.json, Cursor için .cursor/mcp.json, Claude Desktop için
claude_desktop_config.json. VS Code'da sunucunun üstündeki Start'a basın; Claude Code'da /mcp yazıp
connected olduğunu görün. 14 araç listelenmelidir.
4. Türkçe sorun. Örnekler:
5. Haritayı görün. render_map haritayı asistana PNG olarak döner ve ~/mapsql-mcp-output klasörüne kaydeder
(istenirse etkileşimli Leaflet HTML de). Bazı istemciler (ör. VS Code'daki Claude Code paneli) aracın resmini size
göstermez; sunucunun env kısmına MAPSQL_OPEN_MAPS=1 (ya da --open-maps) ekleyin, her harita varsayılan
görüntüleyicide açılır.
Bilmeniz gereken. Asistanın sağlayıcısı (Anthropic, OpenAI vb.) araçların döndürdüğü satırları görür. Kurum dışına
çıkmaması gereken verinin bulunduğu veritabanlarını bağlamayın; --schemas / --layers ile yalnız gereken katmanları açın
ve veritabanı kullanıcısını salt okunur tutun. Demo veri: Natural Earth (kamu malı) ve OpenStreetMap (ODbL), ayrıntı:
demo/ATTRIBUTION.md.
Yazar: Mehmet Veysel Delibaş, CBS yazılım mühendisi (Türkiye).
Code: MIT © 2026 Mehmet Veysel Delibaş. Demo data: Natural Earth (public domain) and OpenStreetMap
(© OpenStreetMap contributors, ODbL); see demo/ATTRIBUTION.md.
Maps rendered with the OSM basemap carry the required attribution.
来源:README.md,提交 da53da3
Server status: PostgreSQL/PostGIS versions, mode (read-only), limits, allowlists. Call once if unsure what is available.
无需输入参数。
START HERE. List the spatial layers (geometry/geography tables & views) with geometry type, SRID, approx. row count, extent and column names. Use `search` to find layers by name/column (e.g. 'road', 'population').
schemasearchDescribe one layer in detail: all columns and types, exact row count, extent, geometry types, the most common values of text columns and min/max of numeric columns. Call this BEFORE filtering so you use real column names and values.
layer必填include_value_samplesReturn a few example features of a layer (random for small tables) to see real data.
nlayer必填geometryFind features by attribute filters (no spatial predicate). Returns GeoJSON + result_id for render_map. Use describe_layer first to learn column names and values.
layer必填limitcolumnsfiltersgeometryorder_bydescendingFeatures of `layer` within `distance_m` METRES of a reference: a lon/lat point OR feature(s) from another layer. Distances are geodesic/metric regardless of the layer's SRID. Results include distance_m, nearest first. If the user did not say what to measure from, or the reference matches several features, ASK the user.
latlonlayer必填limitcolumnsfiltersgeometrydistance_m必填reference_layeruse_all_matchesreference_filtersThe k nearest features of `layer` to a reference (lon/lat point or feature(s) of another layer), with distance_m in metres. Optional max_distance_m. If the user did not say what 'nearest' is relative to, ASK.
klatlonlayer必填columnsfiltersgeometrymax_distance_mreference_layeruse_all_matchesreference_filtersBuffer geometries by a distance in METRES (geodesic). Buffer a point (lon/lat) or the features of a layer (+filters). dissolve=true merges into one polygon (also returns its area_km2). Returns GeoJSON + result_id.
latlonlayerlimitfiltersdissolvedistance_m必填Spatial predicate filter: features of `layer` that intersect / are within / contain / touch / cross / overlap / are disjoint from (a) features of another layer (other_layer + other_filters), (b) a bbox [min_lon,min_lat,max_lon,max_lat], or (c) a GeoJSON geometry. Example: pois within the polygon 'Central Park'. Ask the user if the second operand is unclear.
bboxlayer必填limitcolumnsfiltersgeometryrelationother_layerother_filtersgeojson_geometryBounding box (WGS84) and centre of a layer or a filtered subset. Useful for framing maps or checking coverage.
layer必填filtersGroup-by statistics over a layer: count, count_distinct, sum, avg, min, max, area_km2 (geodesic polygon area), length_km (geodesic line length), optionally grouped by columns and filtered. Returns a table (no geometry).
layer必填limitfiltersmetricsgroup_byorder_bydescendingSpatial join between two layers, per feature of the LEFT layer. mode='count' (default) counts related RIGHT features (e.g. pharmacies per district: left=districts, right=pois, relation='contains'); 'sum'/'avg' aggregate a numeric right_column; 'attach' lists matched pairs with right_columns. relation: intersects | within | contains | dwithin (needs distance_m). Returns the LEFT geometry so it can be mapped (choropleth-like).
modelimitgeometryrelationmin_countdistance_mleft_layer必填order_descright_layer必填left_filtersright_columnright_columns另有 1 个Run a custom READ-ONLY SQL query (single SELECT, PostgreSQL/PostGIS syntax) when the structured tools do not fit. Validated by a SQL parser, executed in a READ ONLY transaction with a timeout and row cap. Geometry columns are returned as GeoJSON (EPSG:4326). Prefer list_layers/describe_layer first; alias every column.
limitquery必填geometryDraw a MAP and return it as a PNG image (with an OpenStreetMap basemap when online). Pass result_ids from earlier tools (find_features, within_distance, nearest, buffer, spatial_join, bbox_of, run_sql ...) - each becomes a coloured layer - or a GeoJSON string/object, or a SQL query that returns a geometry column. Also saves the PNG and, with save_html=true, an interactive Leaflet HTML map to disk. Use this whenever the answer is spatial.
sqltitlewidthheightbasemapgeojsonsave_htmlresult_idslabel_propertyvalue_property已满足适用检查项的 90%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
pip install mapsql-mcp # or: pipx install mapsql-mcp | uvx mapsql-mcpexport DATABASE_URL=postgresql://readonly:secret@localhost:5432/gismapsql-mcp --check # prints PostgreSQL/PostGIS versions and exits
# Oracle Spatial instead (python-oracledb thin mode: no Oracle Client install needed) - see "Oracle Spatial" belowpip install "mapsql-mcp[oracle]"export DATABASE_URL="oracle://MAPSQL_RO:secret@dbhost:1521/ORCLPDB1"mapsql-mcp --check{ "mcpServers": { "postgis": { "command": "uvx", "args": ["mapsql-mcp"], "env": { "DATABASE_URL": "postgresql://readonly:secret@localhost:5432/gis" } } }}claude mcp add postgis -e DATABASE_URL=postgresql://readonly:secret@localhost:5432/gis -- uvx mapsql-mcp{ "mcpServers": { "postgis": { "command": "uvx", "args": ["mapsql-mcp", "--schemas", "public,osm"], "env": { "DATABASE_URL": "postgresql://readonly:secret@localhost:5432/gis" } } }}{ "inputs": [ { "id": "pg-url", "type": "promptString", "description": "PostGIS connection URL", "password": true } ], "servers": { "postgis": { "type": "stdio", "command": "uvx", "args": ["mapsql-mcp", "--schemas", "public,osm"], "env": { "DATABASE_URL": "${input:pg-url}" } } }}mapsql-mcp --transport streamable-http --host 127.0.0.1 --port 8000pipx install "mapsql-mcp[oracle]" # or: pip install "mapsql-mcp[oracle]"export DATABASE_URL=postgresql://readonly:secret@localhost:5432/gis # or oracle://USER:PASS@host:1521/servicemapsql-mcp --checkdocker run -d --name pg -p 55432:5432 -e POSTGRES_PASSWORD=pw postgis/postgis:16-3.4pip install -e .python demo/build_demo_db.py --database-url postgresql://postgres:pw@localhost:55432/postgresexport DATABASE_URL=postgresql://postgres:pw@localhost:55432/postgrespip install "mapsql-mcp[oracle]" # adds oracledb + sqlglotexport MAPSQL_ORACLE_DSN='(description=(retry_count=3)(address=(protocol=tcps)(port=1522)(host=adb.<region>.oraclecloud.com))(connect_data=(service_name=xxxx_mydb_low.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))'export MAPSQL_ORACLE_USER=MAPSQL_RO MAPSQL_ORACLE_PASSWORD='...'mapsql-mcp --check{ "mcpServers": { "oracle-spatial": { "command": "uvx", "args": ["--from", "mapsql-mcp[oracle]", "mapsql-mcp", "--schemas", "GIS"], "env": { "DATABASE_URL": "oracle://MAPSQL_RO:secret@dbhost:1521/ORCLPDB1" } } }}claude mcp add oracle-spatial -e DATABASE_URL=oracle://MAPSQL_RO:secret@dbhost:1521/ORCLPDB1 -- uvx --from "mapsql-mcp[oracle]" mapsql-mcp --schemas GIS{ "inputs": [ { "id": "ora-pw", "type": "promptString", "description": "Oracle password for MAPSQL_RO", "password": true } ], "servers": { "oracle-spatial": { "type": "stdio", "command": "uvx", "args": ["--from", "mapsql-mcp[oracle]", "mapsql-mcp", "--schemas", "GIS", "--no-basemap"], "env": { "MAPSQL_ORACLE_DSN": "dbhost:1521/ORCLPDB1", "MAPSQL_ORACLE_USER": "MAPSQL_RO", "MAPSQL_ORACLE_PASSWORD": "${input:ora-pw}" } } }}; oracle-test.ini[oracle]user = ADMINpassword = ...dsn = (description=...) ; or host:1521/servicepython scripts/oracle_demo_db.py # creates MAPSQL_DEMO + MAPSQL_RO (random passwords are written to the same ini file)python scripts/make_oracle_demo_maps.py --ini oracle-test.ini # the maps in docs/images/oracle_*.pngpython bench/run_bench.py --oracle # no LLM: replays one reference tool call per questionpython bench/run_bench.py --validate-gold # re-checks gold answers against the databasepython bench/run_bench.py --model gpt-4o-mini --api-key-env OPENAI_API_KEYpython bench/run_bench.py --model qwen2.5:7b --base-url http://localhost:11434/v1python -m venv .venv && .venv/bin/pip install -e ".[dev]"# a throwaway PostGIS (never point the tests at a database you care about):docker run -d -p 55432:5432 -e POSTGRES_PASSWORD=pw -e POSTGRES_DB=mapsql_test postgis/postgis:16-3.4export MAPSQL_TEST_DATABASE_URL=postgresql://postgres:pw@localhost:55432/mapsql_testpytest # guard tests need no database; the rest recreate schemas `mt` and `mt_other`pipx install "mapsql-mcp[oracle]" # ya da: pip install "mapsql-mcp[oracle]"export DATABASE_URL=postgresql://salt_okunur:sifre@localhost:5432/cbs # ya da oracle://KULLANICI:SIFRE@sunucu:1521/servismapsql-mcp --check