@cenogram/mcp-server 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -20,12 +20,12 @@ Manage your keys at [cenogram.pl/ustawienia](https://cenogram.pl/ustawienia).
20
20
 
21
21
  ## Installation
22
22
 
23
- Pick your client. All options below use the hosted server no local install needed (except npx/stdio).
23
+ Pick your client. All options below use the hosted server - no local install needed (except npx/stdio).
24
24
 
25
25
  <details open>
26
26
  <summary><strong>Claude Code</strong></summary>
27
27
 
28
- One command zero config files:
28
+ One command - zero config files:
29
29
 
30
30
  ```bash
31
31
  claude mcp add cenogram https://mcp.cenogram.pl/mcp \
@@ -77,7 +77,7 @@ Add to your config file:
77
77
  }
78
78
  ```
79
79
 
80
- **Stdio fallback** (older versions requires Node.js >= 18):
80
+ **Stdio fallback** (older versions - requires Node.js >= 18):
81
81
  ```json
82
82
  {
83
83
  "mcpServers": {
@@ -159,7 +159,7 @@ In VS Code: Settings > Cline > MCP Servers. Add:
159
159
  </details>
160
160
 
161
161
  <details>
162
- <summary><strong>npx (stdio) local/offline</strong></summary>
162
+ <summary><strong>npx (stdio) - local/offline</strong></summary>
163
163
 
164
164
  Requires **Node.js >= 18**. Use this if you want to run the server locally instead of connecting to the hosted one.
165
165
 
@@ -191,7 +191,7 @@ Requires **Node.js >= 18**. Use this if you want to run the server locally inste
191
191
 
192
192
  | Env Variable | Required | Default | Description |
193
193
  |---|---|---|---|
194
- | `CENOGRAM_API_KEY` | **Yes** (stdio) | | API key from [cenogram.pl/api](https://cenogram.pl/api) |
194
+ | `CENOGRAM_API_KEY` | **Yes** (stdio) | - | API key from [cenogram.pl/api](https://cenogram.pl/api) |
195
195
  | `CENOGRAM_API_URL` | No | `https://cenogram.pl` | API base URL |
196
196
  | `MCP_TRANSPORT` | No | `stdio` | Set to `http` for Streamable HTTP mode |
197
197
  | `MCP_PORT` | No | `3002` | HTTP server port (HTTP mode only) |
@@ -235,7 +235,7 @@ You can also use the `--http` CLI flag instead of `MCP_TRANSPORT=http`.
235
235
 
236
236
  - Most cities: use the city name directly (e.g., "Gdansk", "Lublin")
237
237
  - Warsaw: use district names ("Mokotow", "Srodmiescie", "Wola") -- "Warszawa" won't match
238
- - Krakow: use sub-districts ("Krakow-Podgorze", "Krakow-Srodmiescie") plain "Krakow" won't match
238
+ - Krakow: use sub-districts ("Krakow-Podgorze", "Krakow-Srodmiescie") - plain "Krakow" won't match
239
239
  - Use `list_locations` to find valid names
240
240
 
241
241
  ### Property types
@@ -269,13 +269,13 @@ This mimics how a property appraiser finds comparable transactions for valuation
269
269
 
270
270
  ## Troubleshooting
271
271
 
272
- **"Error: CENOGRAM_API_KEY is required"** This only applies to stdio mode. Make sure `CENOGRAM_API_KEY` is set in the `env` block of your MCP config. For HTTP remote, the key goes in the `Authorization` header instead.
272
+ **"Error: CENOGRAM_API_KEY is required"** - This only applies to stdio mode. Make sure `CENOGRAM_API_KEY` is set in the `env` block of your MCP config. For HTTP remote, the key goes in the `Authorization` header instead.
273
273
 
274
- **npx hangs or fails** Check your Node.js version with `node -v`. The stdio mode requires Node.js >= 18. If you're on an older version, use the HTTP remote option instead (no Node.js needed).
274
+ **npx hangs or fails** - Check your Node.js version with `node -v`. The stdio mode requires Node.js >= 18. If you're on an older version, use the HTTP remote option instead (no Node.js needed).
275
275
 
276
- **"Warszawa" returns 0 results** Warsaw uses district names (Mokotow, Wola, Srodmiescie, Bemowo, etc.). Use `list_locations(search="warsz")` to find valid names. Same applies to Krakow (use "Krakow-Podgorze", "Krakow-Srodmiescie", etc.).
276
+ **"Warszawa" returns 0 results** - Warsaw uses district names (Mokotow, Wola, Srodmiescie, Bemowo, etc.). Use `list_locations(search="warsz")` to find valid names. Same applies to Krakow (use "Krakow-Podgorze", "Krakow-Srodmiescie", etc.).
277
277
 
278
- **401 Unauthorized (HTTP mode)** The `Authorization` header must be `Bearer cngrm_...` (with the `Bearer` prefix). Double-check that the full API key is included, not just the prefix.
278
+ **401 Unauthorized (HTTP mode)** - The `Authorization` header must be `Bearer cngrm_...` (with the `Bearer` prefix). Double-check that the full API key is included, not just the prefix.
279
279
 
280
280
  ## Development
281
281
 
package/dist/client-id.js CHANGED
@@ -22,7 +22,7 @@ export function getClientId() {
22
22
  }
23
23
  }
24
24
  catch {
25
- // File doesn't exist or isn't readable generate new
25
+ // File doesn't exist or isn't readable - generate new
26
26
  }
27
27
  // Generate and persist
28
28
  const id = randomUUID();
@@ -31,7 +31,7 @@ export function getClientId() {
31
31
  writeFileSync(CLIENT_ID_FILE, id + "\n", { mode: 0o600 });
32
32
  }
33
33
  catch {
34
- // Read-only fs (Docker, sandbox) use ephemeral ID
34
+ // Read-only fs (Docker, sandbox) - use ephemeral ID
35
35
  }
36
36
  cachedId = id;
37
37
  return id;
package/dist/index.js CHANGED
@@ -16,11 +16,11 @@ catch { /* fallback to hardcoded if dist/ used standalone */ }
16
16
  export function createMcpServer(apiKey) {
17
17
  const server = new McpServer({ name: "cenogram-mcp-server", version: PKG_VERSION }, {
18
18
  instructions: [
19
- "Cenogram MCP Server 7M+ verified real estate transactions from Poland's official RCN registry (Rejestr Cen Nieruchomości). Transaction prices from notarial deeds NOT asking/listing prices. Data from 2003 to present, ~380 counties, refreshed every ~2 weeks.",
19
+ "Cenogram MCP Server - 7M+ verified real estate transactions from Poland's official RCN registry (Rejestr Cen Nieruchomości). Transaction prices from notarial deeds - NOT asking/listing prices. Data from 2003 to present, ~380 counties, refreshed every ~2 weeks.",
20
20
  "",
21
- "CRITICAL District names (ALWAYS verify first):",
21
+ "CRITICAL - District names (ALWAYS verify first):",
22
22
  "- NEVER guess district names. Call list_locations(search=\"city\") first.",
23
- "- Warsaw: use district names (Mokotów, Wola, Śródmieście) \"Warszawa\" returns 0 results",
23
+ "- Warsaw: use district names (Mokotów, Wola, Śródmieście) - \"Warszawa\" returns 0 results",
24
24
  "- Kraków: Kraków-Śródmieście, Kraków-Podgórze, Kraków-Krowodrza, Kraków-Nowa Huta",
25
25
  "- Most cities (Gdańsk, Gdynia, Sopot, Poznań): just the city name, no sub-districts",
26
26
  "",
@@ -29,14 +29,14 @@ export function createMcpServer(apiKey) {
29
29
  "- Compare locations: list_locations → compare_locations (2-5 districts, requires at least one filter e.g. propertyType)",
30
30
  "- Parcel lookup: search_parcels(q, min 3 chars) → search_by_area (use returned lat/lng)",
31
31
  "- Address search: search_transactions(location, street, buildingNumber)",
32
- "- Radius search: search_by_area(lat, lng, radiusKm) for geographic proximity",
33
- "- Polygon search: search_by_polygon coordinates are [longitude, latitude], first=last point, max 500 vertices",
32
+ "- Radius search: search_by_area(lat, lng, radiusKm) - for geographic proximity",
33
+ "- Polygon search: search_by_polygon - coordinates are [longitude, latitude], first=last point, max 500 vertices",
34
34
  "",
35
35
  "Data notes:",
36
36
  "- price_per_m2 only meaningful for apartments (propertyType=\"unit\")",
37
- "- API has no rooms filter use area as proxy (1-room: 20-35m², 2: 35-55m², 3: 55-90m², 4+: 80-130m²), then post-filter by rooms field in results",
37
+ "- API has no rooms filter - use area as proxy (1-room: 20-35m², 2: 35-55m², 3: 55-90m², 4+: 80-130m²), then post-filter by rooms field in results",
38
38
  "- Results paginated (default 10-20). Use page parameter for more.",
39
- "- For §79-compliant export table or interactive map direct user to cenogram.pl",
39
+ "- For §79-compliant export table or interactive map - direct user to cenogram.pl",
40
40
  ].join("\n"),
41
41
  });
42
42
  registerTools(server, apiKey);
package/dist/tools.js CHANGED
@@ -27,7 +27,7 @@ export function registerTools(server, apiKey) {
27
27
  Returns transaction details: address, date, price, area, price/m², property type.
28
28
  Use list_locations first to find valid location names.
29
29
  Example: search for apartments in Mokotów sold in 2024 above 500,000 PLN.`, {
30
- location: z.string().optional().describe("Location name city (e.g. 'Kraków', 'Gdańsk') or district (e.g. 'Mokotów', 'Śródmieście'). For Warsaw, use district names (Mokotów, Wola, etc.) 'Warszawa' won't match. Use list_locations to find valid names."),
30
+ location: z.string().optional().describe("Location name - city (e.g. 'Kraków', 'Gdańsk') or district (e.g. 'Mokotów', 'Śródmieście'). For Warsaw, use district names (Mokotów, Wola, etc.) - 'Warszawa' won't match. Use list_locations to find valid names."),
31
31
  propertyType: z.enum(["land", "building", "developed_land", "unit"]).optional()
32
32
  .describe("Property type filter"),
33
33
  marketType: z.enum(["primary", "secondary"]).optional()
@@ -38,7 +38,7 @@ Example: search for apartments in Mokotów sold in 2024 above 500,000 PLN.`, {
38
38
  dateTo: z.string().optional().describe("End date (YYYY-MM-DD)"),
39
39
  street: z.string().optional().describe("Street name filter (partial match, e.g. 'Puławska', 'Trakt Lubelski')"),
40
40
  buildingNumber: z.string().optional().describe("Building/house number (e.g. '251C', '12A'). Requires location or street to be set."),
41
- parcelId: z.string().optional().describe("Exact parcel ID as returned in search results (e.g. '146518_8.0108.27'). Must match exactly copy from a previous search result's parcel_id field."),
41
+ parcelId: z.string().optional().describe("Exact parcel ID as returned in search results (e.g. '146518_8.0108.27'). Must match exactly - copy from a previous search result's parcel_id field."),
42
42
  minArea: z.number().optional().describe("Minimum area in m²"),
43
43
  maxArea: z.number().optional().describe("Maximum area in m²"),
44
44
  limit: z.number().min(1).max(50).default(10)
@@ -77,7 +77,7 @@ Example: search for apartments in Mokotów sold in 2024 above 500,000 PLN.`, {
77
77
  // ── Tool 2: get_price_statistics ────────────────────────────────────
78
78
  server.tool("get_price_statistics", `Get price per m² statistics by location for residential apartments in Poland.
79
79
  Note: only covers residential units (lokale mieszkalne). For other property types, use search_transactions.
80
- For Warsaw: use district names (Mokotów, Wola) 'Warszawa' won't match any results.`, {
80
+ For Warsaw: use district names (Mokotów, Wola) - 'Warszawa' won't match any results.`, {
81
81
  location: z.string().optional().describe("Filter by location name (case-insensitive partial match). E.g. 'Kraków' matches 'Kraków-Podgórze', 'Kraków-Śródmieście', etc. Omit for all Poland."),
82
82
  }, { readOnlyHint: true }, async (params) => withErrorHandling(async () => {
83
83
  const { data: allRows, creditInfo } = await getPricePerM2(apiKey);
@@ -146,7 +146,7 @@ Returns: total transaction count, date range, breakdown by property type and mar
146
146
  }));
147
147
  // ── Tool 6: list_locations ──────────────────────────────────────────
148
148
  server.tool("list_locations", `List available locations (cities and districts) in the database.
149
- Returns administrative districts for most cities, the district name equals the city name.
149
+ Returns administrative districts - for most cities, the district name equals the city name.
150
150
  For Warsaw: returns district names (Mokotów, Śródmieście, Wola, etc.), not 'Warszawa'.
151
151
  For Kraków: returns sub-districts (Kraków-Podgórze, Kraków-Śródmieście, etc.).
152
152
  Use the search parameter to filter by name.`, {
@@ -236,7 +236,7 @@ Requires at least one filter besides districts (e.g., propertyType).
236
236
  Example: compare Mokotów, Wola, Ursynów for apartments.`, {
237
237
  districts: z.string().min(1).describe("Comma-separated district names to compare (2-5). E.g. 'Mokotów,Wola,Ursynów'"),
238
238
  propertyType: z.enum(["land", "building", "developed_land", "unit"]).optional()
239
- .describe("Property type filter (recommended API requires at least one filter)"),
239
+ .describe("Property type filter (recommended - API requires at least one filter)"),
240
240
  marketType: z.enum(["primary", "secondary"]).optional()
241
241
  .describe("Market type filter"),
242
242
  minPrice: z.number().optional().describe("Minimum price in PLN"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cenogram/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "MCP Server for Polish real estate transaction data (7M+ transactions from RCN)",
5
5
  "type": "module",
6
6
  "bin": {