@cenogram/mcp-server 0.1.2 → 0.1.4

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.
@@ -49,6 +49,7 @@ export interface Transaction {
49
49
  parcel_area: number | null;
50
50
  unit_function: number | null;
51
51
  parcel_id: string | null;
52
+ parcel_number: string | null;
52
53
  county_name: string | null;
53
54
  voivodeship_name: string | null;
54
55
  centroid: {
@@ -103,6 +104,9 @@ export interface TransactionParams {
103
104
  parcelId?: string;
104
105
  propertyType?: number;
105
106
  marketType?: number;
107
+ unitFunction?: number;
108
+ buildingType?: number;
109
+ mpzpDesignation?: string;
106
110
  minPrice?: number;
107
111
  maxPrice?: number;
108
112
  dateFrom?: string;
@@ -138,6 +142,9 @@ export interface SpatialSearchParams {
138
142
  };
139
143
  propertyType?: number;
140
144
  marketType?: number;
145
+ unitFunction?: number;
146
+ buildingType?: number;
147
+ mpzpDesignation?: string;
141
148
  minPrice?: number;
142
149
  maxPrice?: number;
143
150
  dateFrom?: string;
@@ -163,6 +170,7 @@ export interface SpatialFeatureProperties {
163
170
  city: string | null;
164
171
  district: string | null;
165
172
  parcel_area: number | null;
173
+ parcel_number: string | null;
166
174
  }
167
175
  export interface SpatialFeature {
168
176
  type: "Feature";
@@ -192,6 +200,9 @@ export interface CompareParams {
192
200
  districts: string;
193
201
  propertyType?: number;
194
202
  marketType?: number;
203
+ unitFunction?: number;
204
+ buildingType?: number;
205
+ mpzpDesignation?: string;
195
206
  minPrice?: number;
196
207
  maxPrice?: number;
197
208
  dateFrom?: string;
@@ -95,6 +95,9 @@ export function getTransactions(p, apiKey) {
95
95
  parcelId: p.parcelId,
96
96
  propertyType: p.propertyType,
97
97
  marketType: p.marketType,
98
+ unitFunction: p.unitFunction,
99
+ buildingType: p.buildingType,
100
+ mpzpDesignation: p.mpzpDesignation,
98
101
  minPrice: p.minPrice,
99
102
  maxPrice: p.maxPrice,
100
103
  dateFrom: p.dateFrom,
@@ -114,6 +117,9 @@ export function getTransactionsSummary(p, apiKey) {
114
117
  street: p.street,
115
118
  propertyType: p.propertyType,
116
119
  marketType: p.marketType,
120
+ unitFunction: p.unitFunction,
121
+ buildingType: p.buildingType,
122
+ mpzpDesignation: p.mpzpDesignation,
117
123
  minPrice: p.minPrice,
118
124
  maxPrice: p.maxPrice,
119
125
  dateFrom: p.dateFrom,
@@ -141,6 +147,12 @@ export function searchByPolygon(p, apiKey) {
141
147
  body.propertyType = p.propertyType;
142
148
  if (p.marketType != null)
143
149
  body.marketType = p.marketType;
150
+ if (p.unitFunction != null)
151
+ body.unitFunction = p.unitFunction;
152
+ if (p.buildingType != null)
153
+ body.buildingType = p.buildingType;
154
+ if (p.mpzpDesignation)
155
+ body.mpzpDesignation = p.mpzpDesignation;
144
156
  if (p.minPrice != null)
145
157
  body.minPrice = p.minPrice;
146
158
  if (p.maxPrice != null)
@@ -166,6 +178,9 @@ export function compareLocations(p, apiKey) {
166
178
  districts: p.districts,
167
179
  propertyType: p.propertyType,
168
180
  marketType: p.marketType,
181
+ unitFunction: p.unitFunction,
182
+ buildingType: p.buildingType,
183
+ mpzpDesignation: p.mpzpDesignation,
169
184
  minPrice: p.minPrice,
170
185
  maxPrice: p.maxPrice,
171
186
  dateFrom: p.dateFrom,
@@ -50,6 +50,8 @@ function formatTransactionCore(f) {
50
50
  parts.push(price.join(" | "));
51
51
  // Extra details
52
52
  const extra = [];
53
+ if (f.parcel_number)
54
+ extra.push(`Plot no: ${f.parcel_number}`);
53
55
  if (f.rooms != null)
54
56
  extra.push(`Rooms: ${f.rooms}`);
55
57
  if (f.floor != null)
package/dist/index.js CHANGED
@@ -20,8 +20,8 @@ export function createMcpServer(apiKey) {
20
20
  "",
21
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",
24
- "- Kraków: Kraków-Śródmieście, Kraków-Podgórze, Kraków-Krowodrza, Kraków-Nowa Huta",
23
+ "- Warsaw: 'Warszawa' auto-includes all 18 districts. Or use specific: Mokotów, Wola, Śródmieście",
24
+ "- Kraków/Łódź: 'Kraków'/'Łódź' auto-include all sub-districts. Or use specific: Kraków-Podgórze, etc.",
25
25
  "- Most cities (Gdańsk, Gdynia, Sopot, Poznań): just the city name, no sub-districts",
26
26
  "",
27
27
  "Workflows:",
@@ -49,7 +49,7 @@ async function main() {
49
49
  const { createServer } = await import("node:http");
50
50
  const { StreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/streamableHttp.js");
51
51
  const port = parseInt(process.env.MCP_PORT || "3002", 10);
52
- createServer(async (req, res) => {
52
+ const handleHttpRequest = async (req, res) => {
53
53
  try {
54
54
  const pathname = req.url?.split("?")[0];
55
55
  if (pathname === "/mcp") {
@@ -82,6 +82,11 @@ async function main() {
82
82
  res.writeHead(500, { "Content-Type": "application/json" }).end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32603, message: "Internal server error" }, id: null }));
83
83
  }
84
84
  }
85
+ };
86
+ createServer((req, res) => {
87
+ handleHttpRequest(req, res).catch((err) => {
88
+ process.stderr.write(`Unhandled HTTP error: ${String(err)}\n`);
89
+ });
85
90
  }).listen(port, "0.0.0.0", () => {
86
91
  process.stderr.write(`MCP HTTP server on http://0.0.0.0:${port}/mcp\n`);
87
92
  });
@@ -2,7 +2,14 @@ export declare const PROPERTY_TYPES: Record<number, string>;
2
2
  export declare const MARKET_TYPES: Record<number, string>;
3
3
  export declare function mapPropertyType(value: string | undefined): number | undefined;
4
4
  export declare function mapMarketType(value: string | undefined): number | undefined;
5
+ export declare const UNIT_FUNCTIONS: Record<number, string>;
6
+ export declare function mapUnitFunction(value: string | undefined): number | undefined;
7
+ export declare const BUILDING_TYPES: Record<number, string>;
8
+ export declare function mapBuildingType(value: string | undefined): number | undefined;
5
9
  /** Convert lat/lng/radius to bbox [minLng, minLat, maxLng, maxLat] (lng-first!) */
6
10
  export declare function radiusKmToBbox(lat: number, lng: number, radiusKm: number): [number, number, number, number];
7
11
  /** Filter districts by location name (case-insensitive includes match) */
8
12
  export declare function filterByLocation(location: string, districts: string[]): string[];
13
+ export declare const CITY_SUBDISTRICTS: ReadonlyMap<string, readonly string[]>;
14
+ /** Returns sub-districts for known multi-district cities, or [district] for everything else. */
15
+ export declare function expandDistrict(district: string): string[];
package/dist/mappings.js CHANGED
@@ -29,6 +29,58 @@ export function mapMarketType(value) {
29
29
  return undefined;
30
30
  return MARKET_TYPE_MAP[value];
31
31
  }
32
+ // ── Unit function enum maps ─────────────────────────────────────────
33
+ export const UNIT_FUNCTIONS = {
34
+ 1: "Residential (Mieszkalna)",
35
+ 2: "Commercial (Handlowo-usługowa)",
36
+ 3: "Office (Biurowa)",
37
+ 4: "Production (Produkcyjna)",
38
+ 5: "Garage (Garaż)",
39
+ 6: "Other (Inne)",
40
+ };
41
+ const UNIT_FUNCTION_MAP = {
42
+ residential: 1,
43
+ commercial: 2,
44
+ office: 3,
45
+ production: 4,
46
+ garage: 5,
47
+ other: 6,
48
+ };
49
+ export function mapUnitFunction(value) {
50
+ if (!value)
51
+ return undefined;
52
+ return UNIT_FUNCTION_MAP[value];
53
+ }
54
+ // ── Building type enum maps ─────────────────────────────────────────
55
+ export const BUILDING_TYPES = {
56
+ 110: "Residential (Mieszkalny)",
57
+ 121: "Commercial (Handlowo-usługowy)",
58
+ 122: "Industrial (Przemysłowy)",
59
+ 123: "Transport (Transportu i łączności)",
60
+ 124: "Office (Biurowy)",
61
+ 125: "Warehouse (Zbiorniki/Silosy/Magazyny)",
62
+ 126: "Education/Sports (Oświaty i sportu)",
63
+ 127: "Farm/Utility (Gospodarczy)",
64
+ 128: "Hospital (Szpitale)",
65
+ 129: "Other non-residential (Pozostałe niemieszkalne)",
66
+ };
67
+ const BUILDING_TYPE_MAP = {
68
+ residential: 110,
69
+ commercial: 121,
70
+ industrial: 122,
71
+ transport: 123,
72
+ office: 124,
73
+ warehouse: 125,
74
+ education_sports: 126,
75
+ farm_utility: 127,
76
+ hospital: 128,
77
+ other_nonresidential: 129,
78
+ };
79
+ export function mapBuildingType(value) {
80
+ if (!value)
81
+ return undefined;
82
+ return BUILDING_TYPE_MAP[value];
83
+ }
32
84
  // ── Bbox conversion ─────────────────────────────────────────────────
33
85
  /** Convert lat/lng/radius to bbox [minLng, minLat, maxLng, maxLat] (lng-first!) */
34
86
  export function radiusKmToBbox(lat, lng, radiusKm) {
@@ -47,3 +99,23 @@ export function filterByLocation(location, districts) {
47
99
  const lower = location.toLowerCase();
48
100
  return districts.filter((d) => d.toLowerCase().includes(lower));
49
101
  }
102
+ // ── City → sub-district expansion ───────────────────────────────────
103
+ // Keep in sync with api/src/helpers.ts CITY_SUBDISTRICTS (ADR-003).
104
+ // Cities: Warszawa (19), Kraków (5), Łódź (6).
105
+ export const CITY_SUBDISTRICTS = new Map([
106
+ ["Warszawa", [
107
+ "Warszawa", "Bemowo", "Białołęka", "Bielany", "Mokotów", "Ochota",
108
+ "Praga-Południe", "Praga-Północ", "Rembertów", "Śródmieście", "Targówek",
109
+ "Ursus", "Ursynów", "Wawer", "Wesoła", "Wilanów", "Włochy", "Wola", "Żoliborz",
110
+ ]],
111
+ ["Kraków", [
112
+ "Kraków", "Kraków-Krowodrza", "Kraków-Nowa Huta", "Kraków-Podgórze", "Kraków-Śródmieście",
113
+ ]],
114
+ ["Łódź", [
115
+ "Łódź", "Łódź-Bałuty", "Łódź-Górna", "Łódź-Polesie", "Łódź-Śródmieście", "Łódź-Widzew",
116
+ ]],
117
+ ]);
118
+ /** Returns sub-districts for known multi-district cities, or [district] for everything else. */
119
+ export function expandDistrict(district) {
120
+ return CITY_SUBDISTRICTS.get(district)?.slice() ?? [district];
121
+ }
package/dist/tools.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { getStats, getTransactions, getPricePerM2, getDistricts, getPriceHistogram, getTransactionsSummary, searchParcels, searchByPolygon, compareLocations, } from "./api-client.js";
3
3
  import { formatTransactionList, formatMarketOverview, formatPriceStats, formatHistogram, formatParcelResults, formatSpatialResults, formatCompareResults, } from "./formatters.js";
4
- import { mapPropertyType, mapMarketType, radiusKmToBbox, filterByLocation, } from "./mappings.js";
4
+ import { mapPropertyType, mapMarketType, mapUnitFunction, mapBuildingType, radiusKmToBbox, filterByLocation, expandDistrict, CITY_SUBDISTRICTS, } from "./mappings.js";
5
5
  // ── Helpers ─────────────────────────────────────────────────────────
6
6
  function textResponse(text) {
7
7
  return { content: [{ type: "text", text }] };
@@ -32,11 +32,17 @@ export function registerTools(server, apiKey) {
32
32
  Returns transaction details: address, date, price, area, price/m², property type.
33
33
  Use list_locations first to find valid location names.
34
34
  Example: search for apartments in Mokotów sold in 2024 above 500,000 PLN.`, {
35
- 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."),
35
+ location: z.string().optional().describe("Location name - city (e.g. 'Warszawa', 'Kraków', 'Gdańsk') or district (e.g. 'Mokotów', 'Kraków-Podgórze'). 'Warszawa', 'Kraków', 'Łódź' auto-expand to all sub-districts. Use list_locations to find valid names."),
36
36
  propertyType: z.enum(["land", "building", "developed_land", "unit"]).optional()
37
37
  .describe("Property type filter"),
38
38
  marketType: z.enum(["primary", "secondary"]).optional()
39
39
  .describe("Market type: primary (developer) or secondary (resale)"),
40
+ unitFunction: z.enum(["residential", "commercial", "office", "production", "garage", "other"]).optional()
41
+ .describe("Unit/apartment function filter"),
42
+ buildingType: z.enum(["residential", "commercial", "industrial", "transport", "office", "warehouse", "education_sports", "farm_utility", "hospital", "other_nonresidential"]).optional()
43
+ .describe("Building type filter (PKOB classification)"),
44
+ mpzpDesignation: z.string().optional()
45
+ .describe("MPZP zoning designation filter (exact match, e.g. 'budownictwoMieszkanioweWielorodzinne', 'terenObiektowProdukcyjnychSkladowIMagazynow')"),
40
46
  minPrice: z.number().optional().describe("Minimum price in PLN"),
41
47
  maxPrice: z.number().optional().describe("Maximum price in PLN"),
42
48
  dateFrom: z.string().optional().describe("Start date (YYYY-MM-DD)"),
@@ -60,6 +66,9 @@ Example: search for apartments in Mokotów sold in 2024 above 500,000 PLN.`, {
60
66
  district: params.location,
61
67
  propertyType: mapPropertyType(params.propertyType),
62
68
  marketType: mapMarketType(params.marketType),
69
+ unitFunction: mapUnitFunction(params.unitFunction),
70
+ buildingType: mapBuildingType(params.buildingType),
71
+ mpzpDesignation: params.mpzpDesignation,
63
72
  minPrice: params.minPrice,
64
73
  maxPrice: params.maxPrice,
65
74
  dateFrom: params.dateFrom,
@@ -83,14 +92,20 @@ Example: search for apartments in Mokotów sold in 2024 above 500,000 PLN.`, {
83
92
  // ── Tool 2: get_price_statistics ────────────────────────────────────
84
93
  server.tool("get_price_statistics", `Get price per m² statistics by location for residential apartments in Poland.
85
94
  Note: only covers residential units (lokale mieszkalne). For other property types, use search_transactions.
86
- For Warsaw: use district names (Mokotów, Wola) - 'Warszawa' won't match any results.`, {
87
- 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."),
95
+ 'Warszawa'/'Kraków'/'Łódź' auto-expand to all sub-districts (Warszawa=19, Kraków=5, Łódź=6). Other names use partial match.`, {
96
+ location: z.string().optional().describe("Filter by location name. 'Warszawa'/'Kraków'/'Łódź' auto-expand to all sub-districts. Other names use case-insensitive partial match (e.g. 'Wrocł' matches 'Wrocław'). Omit for all Poland."),
88
97
  }, { readOnlyHint: true }, async (params) => withErrorHandling(async () => {
89
98
  requireApiKey(apiKey);
90
99
  const { data: allRows, creditInfo } = await getPricePerM2(apiKey);
91
100
  let rows = allRows;
92
101
  if (params.location) {
93
- rows = rows.filter((r) => filterByLocation(params.location, [r.district]).length > 0);
102
+ if (CITY_SUBDISTRICTS.has(params.location)) {
103
+ const allowed = new Set(expandDistrict(params.location));
104
+ rows = rows.filter((r) => allowed.has(r.district));
105
+ }
106
+ else {
107
+ rows = rows.filter((r) => filterByLocation(params.location, [r.district]).length > 0);
108
+ }
94
109
  }
95
110
  return textResponse(formatPriceStats(rows, params.location) + formatCreditFooter(creditInfo));
96
111
  }));
@@ -109,7 +124,8 @@ Useful for understanding the overall market price structure in Poland.`, {
109
124
  // ── Tool 4: search_by_area ──────────────────────────────────────────
110
125
  server.tool("search_by_area", `Search real estate transactions within a geographic radius.
111
126
  Provide latitude/longitude coordinates and a radius in km.
112
- Example: find apartment sales within 2km of Warsaw's Palace of Culture (lat 52.2317, lng 21.0060).`, {
127
+ Example: find apartment sales within 2km of Warsaw's Palace of Culture (lat 52.2317, lng 21.0060).
128
+ Area filters (minArea/maxArea) work for all propertyType values via COALESCE(usable_area_m2, parcel_area).`, {
113
129
  latitude: z.number().min(49).max(55)
114
130
  .describe("Latitude (Poland range: 49-55)"),
115
131
  longitude: z.number().min(14).max(25)
@@ -120,8 +136,16 @@ Example: find apartment sales within 2km of Warsaw's Palace of Culture (lat 52.2
120
136
  .describe("Property type filter"),
121
137
  marketType: z.enum(["primary", "secondary"]).optional()
122
138
  .describe("Market type filter"),
139
+ unitFunction: z.enum(["residential", "commercial", "office", "production", "garage", "other"]).optional()
140
+ .describe("Unit/apartment function filter"),
141
+ buildingType: z.enum(["residential", "commercial", "industrial", "transport", "office", "warehouse", "education_sports", "farm_utility", "hospital", "other_nonresidential"]).optional()
142
+ .describe("Building type filter (PKOB classification)"),
123
143
  minPrice: z.number().optional().describe("Minimum price in PLN"),
124
144
  maxPrice: z.number().optional().describe("Maximum price in PLN"),
145
+ minArea: z.number().optional()
146
+ .describe("Minimum area in m² (usable_area_m2 for units, parcel_area for land)"),
147
+ maxArea: z.number().optional()
148
+ .describe("Maximum area in m²"),
125
149
  dateFrom: z.string().optional().describe("Start date (YYYY-MM-DD)"),
126
150
  dateTo: z.string().optional().describe("End date (YYYY-MM-DD)"),
127
151
  limit: z.number().min(1).max(50).default(20)
@@ -133,8 +157,12 @@ Example: find apartment sales within 2km of Warsaw's Palace of Culture (lat 52.2
133
157
  bbox: bbox.join(","),
134
158
  propertyType: mapPropertyType(params.propertyType),
135
159
  marketType: mapMarketType(params.marketType),
160
+ unitFunction: mapUnitFunction(params.unitFunction),
161
+ buildingType: mapBuildingType(params.buildingType),
136
162
  minPrice: params.minPrice,
137
163
  maxPrice: params.maxPrice,
164
+ minArea: params.minArea,
165
+ maxArea: params.maxArea,
138
166
  dateFrom: params.dateFrom,
139
167
  dateTo: params.dateTo,
140
168
  limit: params.limit,
@@ -213,6 +241,12 @@ Example: {"type":"Polygon","coordinates":[[[21.0,52.2],[21.01,52.2],[21.01,52.21
213
241
  .describe("Property type filter"),
214
242
  marketType: z.enum(["primary", "secondary"]).optional()
215
243
  .describe("Market type filter"),
244
+ unitFunction: z.enum(["residential", "commercial", "office", "production", "garage", "other"]).optional()
245
+ .describe("Unit/apartment function filter"),
246
+ buildingType: z.enum(["residential", "commercial", "industrial", "transport", "office", "warehouse", "education_sports", "farm_utility", "hospital", "other_nonresidential"]).optional()
247
+ .describe("Building type filter (PKOB classification)"),
248
+ mpzpDesignation: z.string().optional()
249
+ .describe("MPZP zoning designation filter (exact match)"),
216
250
  minPrice: z.number().optional().describe("Minimum price in PLN"),
217
251
  maxPrice: z.number().optional().describe("Maximum price in PLN"),
218
252
  dateFrom: z.string().optional().describe("Start date (YYYY-MM-DD)"),
@@ -229,6 +263,9 @@ Example: {"type":"Polygon","coordinates":[[[21.0,52.2],[21.01,52.2],[21.01,52.21
229
263
  polygon: params.polygon,
230
264
  propertyType: mapPropertyType(params.propertyType),
231
265
  marketType: mapMarketType(params.marketType),
266
+ unitFunction: mapUnitFunction(params.unitFunction),
267
+ buildingType: mapBuildingType(params.buildingType),
268
+ mpzpDesignation: params.mpzpDesignation,
232
269
  minPrice: params.minPrice,
233
270
  maxPrice: params.maxPrice,
234
271
  dateFrom: params.dateFrom,
@@ -252,6 +289,12 @@ Example: compare Mokotów, Wola, Ursynów for apartments.`, {
252
289
  .describe("Property type filter (recommended - API requires at least one filter)"),
253
290
  marketType: z.enum(["primary", "secondary"]).optional()
254
291
  .describe("Market type filter"),
292
+ unitFunction: z.enum(["residential", "commercial", "office", "production", "garage", "other"]).optional()
293
+ .describe("Unit/apartment function filter"),
294
+ buildingType: z.enum(["residential", "commercial", "industrial", "transport", "office", "warehouse", "education_sports", "farm_utility", "hospital", "other_nonresidential"]).optional()
295
+ .describe("Building type filter (PKOB classification)"),
296
+ mpzpDesignation: z.string().optional()
297
+ .describe("MPZP zoning designation prefix filter (e.g. 'terenRolniczy', 'budownictwoMieszkanioweJednorodzinne', 'budownictwoMieszkanioweWielorodzinne')"),
255
298
  minPrice: z.number().optional().describe("Minimum price in PLN"),
256
299
  maxPrice: z.number().optional().describe("Maximum price in PLN"),
257
300
  dateFrom: z.string().optional().describe("Start date (YYYY-MM-DD)"),
@@ -265,6 +308,9 @@ Example: compare Mokotów, Wola, Ursynów for apartments.`, {
265
308
  districts: params.districts,
266
309
  propertyType: mapPropertyType(params.propertyType),
267
310
  marketType: mapMarketType(params.marketType),
311
+ unitFunction: mapUnitFunction(params.unitFunction),
312
+ buildingType: mapBuildingType(params.buildingType),
313
+ mpzpDesignation: params.mpzpDesignation,
268
314
  minPrice: params.minPrice,
269
315
  maxPrice: params.maxPrice,
270
316
  dateFrom: params.dateFrom,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cenogram/mcp-server",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "MCP Server for Polish real estate transaction data (7M+ transactions from RCN)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,23 +10,37 @@
10
10
  "dist"
11
11
  ],
12
12
  "scripts": {
13
- "build": "tsc",
13
+ "build": "tsc -p tsconfig.build.json",
14
14
  "dev": "tsx src/index.ts",
15
15
  "test": "vitest run",
16
- "prepublishOnly": "npm run build"
16
+ "lint": "eslint .",
17
+ "typecheck": "tsc --noEmit",
18
+ "check": "tsc --noEmit && eslint .",
19
+ "prepublishOnly": "npm run lint && npm run test && npm run build"
17
20
  },
18
21
  "dependencies": {
19
22
  "@modelcontextprotocol/sdk": "^1.28.0",
20
23
  "zod": "^3.24.0"
21
24
  },
22
25
  "devDependencies": {
26
+ "@eslint/js": "^9.13.0",
23
27
  "@types/node": "^22.0.0",
28
+ "eslint": "^9.13.0",
24
29
  "tsx": "^4.19.0",
25
30
  "typescript": "^5.6.0",
26
- "vitest": "^3.0.0"
31
+ "typescript-eslint": "^8.11.0",
32
+ "vitest": "^4.1.4"
27
33
  },
28
34
  "mcpName": "pl.cenogram/mcp-server",
29
- "keywords": ["mcp", "real-estate", "poland", "rcn", "nieruchomosci", "property", "transactions"],
35
+ "keywords": [
36
+ "mcp",
37
+ "real-estate",
38
+ "poland",
39
+ "rcn",
40
+ "nieruchomosci",
41
+ "property",
42
+ "transactions"
43
+ ],
30
44
  "license": "MIT",
31
45
  "publishConfig": {
32
46
  "access": "public"