Atlas 数据查询 MCP 服务

通过 Model Context Protocol 提供经 CID 验证的 Atlas 县级土地/财产数据查询,并将数据同步到本地 SQLite 或托管 Postgres 后通过只读 SQL 和词典工具访问。

  • by elephant-xyz
  • TypeScript
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 elephant-xyz/elephant-mcp

使用说明

Elephant MCP

Elephant MCP exposes lexicon tools and CID-verified Atlas county data through the Model Context Protocol. Atlas data is synchronized into local SQLite or hosted Postgres before tools query it; request handlers never query remote Parquet files.

Contents

Requirements

  • Node.js 22.18 or newer
  • Network access to the configured Atlas gateways
  • Postgres/Neon only for hosted deployments

Run locally

npm install
npm run build
npm start

The stdio server stores Atlas data separately from verified-script embeddings under the Elephant MCP application-data directory. It begins one Atlas sync on startup. Atlas-backed tool calls wait for the accepted SQL snapshot.

MCP client configuration:

{
  "mcpServers": {
    "elephant": {
      "command": "npx",
      "args": ["-y", "@elephant-xyz/mcp@2"]
    }
  }
}

Synchronize Atlas

Build first, then invoke the packaged CLI subcommand:

npm run build
npm run sync

The command:

  1. Resolves the Atlas IPNS index through the configured gateways.
  2. Computes the index CID from its bytes.
  3. Verifies CountyIndex, CountyTables, and UnixFS Parquet CIDs.
  4. Reads changed Parquet parts through DuckDB and loads them into SQL in batches.
  5. Applies replacements and withdrawals atomically.
  6. Prints the synchronized index CID and per-group counts.

An unchanged index performs no database writes.

Storage layout

The database holds one table per CountyTables table, named exactly as published: one per lexicon class (property, address, company, ...), one per relationship type (property_has_address, ...), and properties for the per-property data-group roots. Columns come from the Parquet parts (DESCRIBE read_parquet with union_by_name; new columns are added with ALTER TABLE ... ADD COLUMN) plus state, county, and data_group.

Primary keys:

Table Key
lexicon class (state, county, data_group, cid)
relationship (state, county, data_group, relationship_cid)
properties (state, county, data_group, property_cid)

export-tables writes each entity and relationship once per archive, with property_cid set to the first property that referenced it. getAtlasProperty therefore seeds with the property's own rows and follows relationship rows from_cid to to_cid inside the scope (to a fixpoint or depth 8) to gather people, companies, and addresses shared with earlier properties. Loading a group deletes its state/county/data_group scope and reinserts it with ON CONFLICT DO UPDATE; withdrawing a group is the delete alone. Both happen in one transaction.

Control tables: atlas_state (one row per loaded county/data group with its archive, tables, and schema CIDs) and atlas_sync_state (the accepted index CID). The atlas_ prefix is reserved; every other table in the database is discovered from the catalog as Atlas content.

Hosted deployment

Set DATABASE_URL to a direct postgres:// or postgresql:// URL and run mcp sync as a separate job. The HTTP deployment should use a read-only database credential. HTTP requests never resolve IPNS, download parts, or run DuckDB ETL.

Start the Node HTTP transport with:

npm run build
npm run start:http

The MCP endpoint is POST /mcp; GET /health is public. Set MCP_HTTP_AUTH_TOKEN to protect MCP routes.

Tools

Atlas SQL:

  • listAtlasCounties
  • listAtlasProperties
  • getAtlasProperty
  • getAtlasDatasetInfo
  • getAtlasSchema
  • queryAtlas

Lexicon and verified scripts:

  • listClassesByDataGroup
  • listPropertiesByClassName
  • getPropertySchema
  • getVerifiedScriptExamples

Atlas data tools require explicit state, county, and dataGroup scope (county keys repeat across states). queryAtlas accepts one read-only SELECT that names the synchronized tables directly (property, address, property_has_address, properties, ...); each one is shadowed by a CTE filtered to the requested state, county, and data group, and any identifier that is not one of those tables, their columns, an alias, a function, or a SQL keyword is rejected, so atlas_state, catalogs, and schema-qualified names fail closed. Responses include the Atlas index, archive, tables, and schema CIDs.

In the lexicon, coordinates live on geometry, parcel numbers on parcel and property, and values on tax; reach them by JOIN through the relationship tables. Properties in a bounding box with their market value:

SELECT p.parcel_identifier, g.latitude, g.longitude,
       t.property_market_value_amount
FROM property p
JOIN property_has_address pa ON pa.from_cid = p.cid
JOIN address_has_geometry ag ON ag.from_cid = pa.to_cid
JOIN geometry g ON g.cid = ag.to_cid
LEFT JOIN property_has_tax pt ON pt.from_cid = p.cid
LEFT JOIN tax t ON t.cid = pt.to_cid
WHERE g.latitude BETWEEN 30.2 AND 30.4
  AND g.longitude BETWEEN -81.8 AND -81.5

Replace the SELECT list with count(*) and sum(t.property_market_value_amount) to aggregate over the area.

Configuration

Variable Purpose Default
ATLAS_IPNS Canonical Atlas IPNS name k51qzi5uqu5dhzmj1jtn06idud425ozwdjjjn4eu7q01g2t814h7rw4du0nd04
ATLAS_GATEWAYS Comma-separated gateway origins in retry order Filebase, IPFS.io, dweb.link, w3s.link
DATABASE_URL Atlas SQLite or Postgres target Separate SQLite file under the application-data directory
MCP_HTTP_AUTH_TOKEN Bearer token for HTTP MCP routes Unset
LOG_LEVEL error, warn, info, or debug info
OPENAI_API_KEY OpenAI embeddings for verified scripts Optional
AI_GATEWAY_API_KEY / VERCEL_OIDC_TOKEN Vercel AI Gateway embeddings Optional
AWS credential chain Bedrock embeddings Optional

DATABASE_URL accepts file:, postgres://, and postgresql://. Database credentials are never logged.

Development

npm run build
npm run test:ci
npm run lint
npm run format:check

Atlas tests cover shape validation, CID verification, SQLite synchronization, idempotence, column evolution, shared content, and withdrawal. The live Atlas and hosted Neon tests are environment-gated.