propstack-mcp-server 1.0.0
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/LICENSE +21 -0
- package/README.md +321 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/propstack-client.d.ts +24 -0
- package/dist/propstack-client.d.ts.map +1 -0
- package/dist/propstack-client.js +99 -0
- package/dist/propstack-client.js.map +1 -0
- package/dist/tools/activities.d.ts +4 -0
- package/dist/tools/activities.d.ts.map +1 -0
- package/dist/tools/activities.js +177 -0
- package/dist/tools/activities.js.map +1 -0
- package/dist/tools/admin.d.ts +4 -0
- package/dist/tools/admin.d.ts.map +1 -0
- package/dist/tools/admin.js +148 -0
- package/dist/tools/admin.js.map +1 -0
- package/dist/tools/composites.d.ts +4 -0
- package/dist/tools/composites.d.ts.map +1 -0
- package/dist/tools/composites.js +807 -0
- package/dist/tools/composites.js.map +1 -0
- package/dist/tools/contacts.d.ts +4 -0
- package/dist/tools/contacts.d.ts.map +1 -0
- package/dist/tools/contacts.js +386 -0
- package/dist/tools/contacts.js.map +1 -0
- package/dist/tools/deals.d.ts +4 -0
- package/dist/tools/deals.d.ts.map +1 -0
- package/dist/tools/deals.js +230 -0
- package/dist/tools/deals.js.map +1 -0
- package/dist/tools/documents.d.ts +4 -0
- package/dist/tools/documents.d.ts.map +1 -0
- package/dist/tools/documents.js +109 -0
- package/dist/tools/documents.js.map +1 -0
- package/dist/tools/emails.d.ts +4 -0
- package/dist/tools/emails.d.ts.map +1 -0
- package/dist/tools/emails.js +111 -0
- package/dist/tools/emails.js.map +1 -0
- package/dist/tools/helpers.d.ts +39 -0
- package/dist/tools/helpers.d.ts.map +1 -0
- package/dist/tools/helpers.js +160 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/lookups.d.ts +4 -0
- package/dist/tools/lookups.d.ts.map +1 -0
- package/dist/tools/lookups.js +333 -0
- package/dist/tools/lookups.js.map +1 -0
- package/dist/tools/projects.d.ts +4 -0
- package/dist/tools/projects.d.ts.map +1 -0
- package/dist/tools/projects.js +104 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/properties.d.ts +4 -0
- package/dist/tools/properties.d.ts.map +1 -0
- package/dist/tools/properties.js +397 -0
- package/dist/tools/properties.js.map +1 -0
- package/dist/tools/relationships.d.ts +4 -0
- package/dist/tools/relationships.d.ts.map +1 -0
- package/dist/tools/relationships.js +55 -0
- package/dist/tools/relationships.js.map +1 -0
- package/dist/tools/search-profiles.d.ts +4 -0
- package/dist/tools/search-profiles.d.ts.map +1 -0
- package/dist/tools/search-profiles.js +345 -0
- package/dist/tools/search-profiles.js.map +1 -0
- package/dist/tools/tasks.d.ts +4 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +251 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/types/propstack.d.ts +444 -0
- package/dist/types/propstack.d.ts.map +1 -0
- package/dist/types/propstack.js +3 -0
- package/dist/types/propstack.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { textResult, errorResult, fmt, fmtPrice, stripUndefined } from "./helpers.js";
|
|
3
|
+
// ── Response formatting ──────────────────────────────────────────────
|
|
4
|
+
const FEELING_LABELS = ["none", "cold", "warm", "hot"];
|
|
5
|
+
function formatDeal(d) {
|
|
6
|
+
const clientName = d.client
|
|
7
|
+
? (fmt(d.client.name) !== "none" ? fmt(d.client.name) : [fmt(d.client.first_name, ""), fmt(d.client.last_name, "")].filter(Boolean).join(" ") || "Unnamed")
|
|
8
|
+
: `Contact #${d.client_id ?? "?"}`;
|
|
9
|
+
const propertyTitle = d.property
|
|
10
|
+
? fmt(d.property.title, "Untitled")
|
|
11
|
+
: `Property #${d.property_id ?? "?"}`;
|
|
12
|
+
const lines = [
|
|
13
|
+
`**Deal #${d.id}**: ${clientName} → ${propertyTitle}`,
|
|
14
|
+
`Stage: ${fmt(d.deal_stage_id)} | Pipeline: ${fmt(d.deal_pipeline_id)}`,
|
|
15
|
+
`Category: ${fmt(d.category)}`,
|
|
16
|
+
d.sold_price ? `Price: ${fmtPrice(d.sold_price)}` : null,
|
|
17
|
+
d.feeling !== null && d.feeling !== undefined
|
|
18
|
+
? `Feeling: ${FEELING_LABELS[d.feeling] ?? d.feeling}`
|
|
19
|
+
: null,
|
|
20
|
+
`Broker: ${fmt(d.broker_id, "unassigned")}`,
|
|
21
|
+
d.note ? `Note: ${d.note}` : null,
|
|
22
|
+
d.date ? `Date: ${d.date}` : null,
|
|
23
|
+
d.reservation_reason_id ? `Cancellation reason ID: ${d.reservation_reason_id}` : null,
|
|
24
|
+
`Created: ${fmt(d.created_at)}`,
|
|
25
|
+
];
|
|
26
|
+
// Show expanded contact details
|
|
27
|
+
if (d.client) {
|
|
28
|
+
lines.push(`Contact: ${clientName} (ID: ${d.client.id}, Email: ${fmt(d.client.email)}, Phone: ${fmt(d.client.phone ?? d.client.home_cell)})`);
|
|
29
|
+
}
|
|
30
|
+
// Show expanded property details
|
|
31
|
+
if (d.property) {
|
|
32
|
+
const addr = [fmt(d.property.street, ""), fmt(d.property.house_number, "")].filter(Boolean).join(" ");
|
|
33
|
+
const city = [fmt(d.property.zip_code, ""), fmt(d.property.city, "")].filter(Boolean).join(" ");
|
|
34
|
+
const fullAddr = [addr, city].filter(Boolean).join(", ");
|
|
35
|
+
lines.push(`Property: ${propertyTitle} (ID: ${d.property.id}, ${fullAddr || "no address"}, ${fmtPrice(d.property.price)})`);
|
|
36
|
+
}
|
|
37
|
+
return lines.filter(Boolean).join("\n");
|
|
38
|
+
}
|
|
39
|
+
function formatDealRow(d) {
|
|
40
|
+
const clientName = d.client
|
|
41
|
+
? (fmt(d.client.name) !== "none" ? fmt(d.client.name) : [fmt(d.client.first_name, ""), fmt(d.client.last_name, "")].filter(Boolean).join(" ") || "Unnamed")
|
|
42
|
+
: String(d.client_id ?? "?");
|
|
43
|
+
const propertyTitle = d.property
|
|
44
|
+
? fmt(d.property.title, "—")
|
|
45
|
+
: String(d.property_id ?? "?");
|
|
46
|
+
return `| ${d.id} | ${clientName} | ${propertyTitle} | ${fmt(d.deal_stage_id)} | ${fmt(d.category)} | ${fmt(d.feeling !== null && d.feeling !== undefined ? (FEELING_LABELS[d.feeling] ?? d.feeling) : null)} | ${fmt(d.created_at)} |`;
|
|
47
|
+
}
|
|
48
|
+
// ── Tool registration ────────────────────────────────────────────────
|
|
49
|
+
export function registerDealTools(server, client) {
|
|
50
|
+
// ── search_deals ────────────────────────────────────────────────
|
|
51
|
+
server.tool("search_deals", `Search and filter deals (contact↔property relationships) in Propstack.
|
|
52
|
+
|
|
53
|
+
Use this tool to:
|
|
54
|
+
- Show all deals in a specific pipeline stage
|
|
55
|
+
- Find deals for a contact or property
|
|
56
|
+
- Track deal pipeline progress for a project
|
|
57
|
+
- Find lost deals and cancellation reasons
|
|
58
|
+
- Filter by broker, team, feeling (cold/warm/hot)
|
|
59
|
+
|
|
60
|
+
A "deal" represents an interested contact linked to a property at a
|
|
61
|
+
specific stage in a sales/rental pipeline (e.g. Anfrage → Besichtigung
|
|
62
|
+
→ Reserviert → Notartermin → Verkauft).
|
|
63
|
+
|
|
64
|
+
Use include="client,property" to get expanded contact and property
|
|
65
|
+
details in one request.
|
|
66
|
+
|
|
67
|
+
Common queries:
|
|
68
|
+
- All active deals: category="qualified"
|
|
69
|
+
- Lost deals this month: category="lost" + created_at_from
|
|
70
|
+
- Deals for a property: property_id=123
|
|
71
|
+
- Pipeline view: deal_pipeline_id + sort_by=deal_stage_id`, {
|
|
72
|
+
client_id: z.number().optional()
|
|
73
|
+
.describe("Filter by contact ID"),
|
|
74
|
+
property_id: z.number().optional()
|
|
75
|
+
.describe("Filter by property ID"),
|
|
76
|
+
project_id: z.number().optional()
|
|
77
|
+
.describe("Filter by project ID"),
|
|
78
|
+
broker_id: z.number().optional()
|
|
79
|
+
.describe("Filter by assigned broker ID"),
|
|
80
|
+
deal_stage_ids: z.array(z.number()).optional()
|
|
81
|
+
.describe("Filter by deal stage IDs (pipeline steps)"),
|
|
82
|
+
deal_pipeline_id: z.number().optional()
|
|
83
|
+
.describe("Filter by deal pipeline ID"),
|
|
84
|
+
category: z.enum(["qualified", "unqualified", "lost"]).optional()
|
|
85
|
+
.describe("Deal category: qualified (active), unqualified (not yet), lost (cancelled/rejected)"),
|
|
86
|
+
reservation_reason_ids: z.array(z.number()).optional()
|
|
87
|
+
.describe("Filter by cancellation/reservation reason IDs"),
|
|
88
|
+
client_source_id: z.number().optional()
|
|
89
|
+
.describe("Filter by lead source ID"),
|
|
90
|
+
team_id: z.number().optional()
|
|
91
|
+
.describe("Filter by team ID"),
|
|
92
|
+
property_broker_ids: z.array(z.number()).optional()
|
|
93
|
+
.describe("Filter by property's assigned broker IDs"),
|
|
94
|
+
client_broker_ids: z.array(z.number()).optional()
|
|
95
|
+
.describe("Filter by contact's assigned broker IDs"),
|
|
96
|
+
feeling_from: z.number().optional()
|
|
97
|
+
.describe("Minimum feeling score (0=none, 1=cold, 2=warm, 3=hot)"),
|
|
98
|
+
feeling_to: z.number().optional()
|
|
99
|
+
.describe("Maximum feeling score"),
|
|
100
|
+
created_at_from: z.string().optional()
|
|
101
|
+
.describe("Filter deals created after this date (ISO 8601)"),
|
|
102
|
+
created_at_to: z.string().optional()
|
|
103
|
+
.describe("Filter deals created before this date (ISO 8601)"),
|
|
104
|
+
start_date_from: z.string().optional()
|
|
105
|
+
.describe("Filter by deal start date from (ISO 8601)"),
|
|
106
|
+
start_date_to: z.string().optional()
|
|
107
|
+
.describe("Filter by deal start date to (ISO 8601)"),
|
|
108
|
+
show_archived_clients: z.boolean().optional()
|
|
109
|
+
.describe("Include deals with archived contacts"),
|
|
110
|
+
hide_archived_properties: z.boolean().optional()
|
|
111
|
+
.describe("Exclude deals with archived properties"),
|
|
112
|
+
include: z.string().optional()
|
|
113
|
+
.describe("Comma-separated related data to expand: 'client', 'property', or 'client,property'"),
|
|
114
|
+
sort_by: z.string().optional()
|
|
115
|
+
.describe("Field to sort results by"),
|
|
116
|
+
order: z.enum(["asc", "desc"]).optional()
|
|
117
|
+
.describe("Sort order (default: desc)"),
|
|
118
|
+
page: z.number().optional()
|
|
119
|
+
.describe("Page number (default: 1)"),
|
|
120
|
+
per_page: z.number().optional()
|
|
121
|
+
.describe("Results per page (default: 25)"),
|
|
122
|
+
}, async (args) => {
|
|
123
|
+
try {
|
|
124
|
+
const res = await client.get("/client_properties", { params: args });
|
|
125
|
+
if (!res.data || res.data.length === 0) {
|
|
126
|
+
return textResult("No deals found matching your criteria.");
|
|
127
|
+
}
|
|
128
|
+
const header = res.meta?.total_count !== undefined
|
|
129
|
+
? `Found ${res.meta.total_count} deals (showing ${res.data.length}):\n\n`
|
|
130
|
+
: `Found ${res.data.length} deals:\n\n`;
|
|
131
|
+
const table = [
|
|
132
|
+
"| ID | Contact | Property | Stage | Category | Feeling | Created |",
|
|
133
|
+
"|---|---|---|---|---|---|---|",
|
|
134
|
+
...res.data.map(formatDealRow),
|
|
135
|
+
].join("\n");
|
|
136
|
+
return textResult(header + table);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
return errorResult("Deal", err);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
// ── create_deal ─────────────────────────────────────────────────
|
|
143
|
+
server.tool("create_deal", `Create a deal linking an interested contact to a property in Propstack.
|
|
144
|
+
|
|
145
|
+
A deal represents a contact's interest in a property and tracks it
|
|
146
|
+
through pipeline stages (e.g. Anfrage → Besichtigung → Reserviert →
|
|
147
|
+
Notartermin → Verkauft).
|
|
148
|
+
|
|
149
|
+
Use this tool after:
|
|
150
|
+
- A viewing to formalize interest
|
|
151
|
+
- A contact inquiry about a property
|
|
152
|
+
- Moving a lead into the sales pipeline
|
|
153
|
+
|
|
154
|
+
Requires client_id, property_id, and deal_stage_id. Use list_pipelines or
|
|
155
|
+
get_pipeline to find valid pipeline and stage IDs.`, {
|
|
156
|
+
client_id: z.number()
|
|
157
|
+
.describe("Contact ID (required)"),
|
|
158
|
+
property_id: z.number()
|
|
159
|
+
.describe("Property ID (required)"),
|
|
160
|
+
deal_stage_id: z.number()
|
|
161
|
+
.describe("Pipeline stage ID (required — use list_pipelines or get_pipeline to look up)"),
|
|
162
|
+
broker_id: z.number().optional()
|
|
163
|
+
.describe("Assigned broker ID"),
|
|
164
|
+
deal_pipeline_id: z.number().optional()
|
|
165
|
+
.describe("Pipeline ID (if multiple pipelines exist)"),
|
|
166
|
+
sold_price: z.number().optional()
|
|
167
|
+
.describe("Expected or agreed price"),
|
|
168
|
+
note: z.string().optional()
|
|
169
|
+
.describe("Free-text note about this deal"),
|
|
170
|
+
date: z.string().optional()
|
|
171
|
+
.describe("Deal date (ISO 8601)"),
|
|
172
|
+
feeling: z.number().optional()
|
|
173
|
+
.describe("Feeling score: 0=none, 1=cold, 2=warm, 3=hot"),
|
|
174
|
+
}, async (args) => {
|
|
175
|
+
try {
|
|
176
|
+
const deal = await client.post("/client_properties", { body: { client_property: stripUndefined(args) } });
|
|
177
|
+
return textResult(`Deal created successfully.\n\n${formatDeal(deal)}`);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
return errorResult("Deal", err);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
// ── update_deal ─────────────────────────────────────────────────
|
|
184
|
+
server.tool("update_deal", `Update an existing deal in Propstack.
|
|
185
|
+
|
|
186
|
+
Use this tool to:
|
|
187
|
+
- Move a deal to the next pipeline stage (change deal_stage_id)
|
|
188
|
+
- Update expected/agreed price
|
|
189
|
+
- Add or update notes
|
|
190
|
+
- Change broker assignment
|
|
191
|
+
- Update feeling score after contact
|
|
192
|
+
- Record cancellation reason
|
|
193
|
+
|
|
194
|
+
Only provide the fields you want to change.`, {
|
|
195
|
+
id: z.number()
|
|
196
|
+
.describe("Deal ID to update"),
|
|
197
|
+
client_id: z.number().optional()
|
|
198
|
+
.describe("Contact ID"),
|
|
199
|
+
property_id: z.number().optional()
|
|
200
|
+
.describe("Property ID"),
|
|
201
|
+
deal_stage_id: z.number().optional()
|
|
202
|
+
.describe("Pipeline stage ID — change this to move through pipeline"),
|
|
203
|
+
broker_id: z.number().optional()
|
|
204
|
+
.describe("Assigned broker ID"),
|
|
205
|
+
deal_pipeline_id: z.number().optional()
|
|
206
|
+
.describe("Pipeline ID"),
|
|
207
|
+
sold_price: z.number().optional()
|
|
208
|
+
.describe("Expected or agreed price"),
|
|
209
|
+
note: z.string().optional()
|
|
210
|
+
.describe("Free-text note about this deal"),
|
|
211
|
+
date: z.string().optional()
|
|
212
|
+
.describe("Deal date (ISO 8601)"),
|
|
213
|
+
feeling: z.number().optional()
|
|
214
|
+
.describe("Feeling score: 0=none, 1=cold, 2=warm, 3=hot"),
|
|
215
|
+
category: z.enum(["qualified", "unqualified", "lost"]).optional()
|
|
216
|
+
.describe("Deal category"),
|
|
217
|
+
reservation_reason_id: z.number().optional()
|
|
218
|
+
.describe("Cancellation/reservation reason ID (for lost deals)"),
|
|
219
|
+
}, async (args) => {
|
|
220
|
+
try {
|
|
221
|
+
const { id, ...fields } = args;
|
|
222
|
+
const deal = await client.put(`/client_properties/${id}`, { body: { client_property: stripUndefined(fields) } });
|
|
223
|
+
return textResult(`Deal updated successfully.\n\n${formatDeal(deal)}`);
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
return errorResult("Deal", err);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=deals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deals.js","sourceRoot":"","sources":["../../src/tools/deals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { PropstackClient } from "../propstack-client.js";
|
|
3
|
+
export declare function registerDocumentTools(server: McpServer, client: PropstackClient): void;
|
|
4
|
+
//# sourceMappingURL=documents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/tools/documents.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AA2B9D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAwGtF"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { textResult, errorResult, fmt, stripUndefined } from "./helpers.js";
|
|
3
|
+
// ── Response formatting ──────────────────────────────────────────────
|
|
4
|
+
function formatDocument(d) {
|
|
5
|
+
const flags = [];
|
|
6
|
+
if (d.is_floorplan)
|
|
7
|
+
flags.push("floorplan");
|
|
8
|
+
if (d.is_exposee)
|
|
9
|
+
flags.push("exposé");
|
|
10
|
+
if (d.is_private)
|
|
11
|
+
flags.push("private");
|
|
12
|
+
if (d.on_landing_page)
|
|
13
|
+
flags.push("landing page");
|
|
14
|
+
const lines = [
|
|
15
|
+
`**${fmt(d.title ?? d.name, "Untitled")}** (ID: ${d.id})`,
|
|
16
|
+
fmt(d.url, "") ? `URL: ${fmt(d.url)}` : null,
|
|
17
|
+
flags.length ? `Flags: ${flags.join(", ")}` : null,
|
|
18
|
+
d.tags?.length ? `Tags: ${d.tags.join(", ")}` : null,
|
|
19
|
+
d.broker_id ? `Broker ID: ${d.broker_id}` : null,
|
|
20
|
+
`Created: ${fmt(d.created_at)}`,
|
|
21
|
+
];
|
|
22
|
+
return lines.filter(Boolean).join("\n");
|
|
23
|
+
}
|
|
24
|
+
// ── Tool registration ────────────────────────────────────────────────
|
|
25
|
+
export function registerDocumentTools(server, client) {
|
|
26
|
+
// ── list_documents ──────────────────────────────────────────────
|
|
27
|
+
server.tool("list_documents", `List documents attached to a property, project, or contact.
|
|
28
|
+
|
|
29
|
+
Documents include floor plans (Grundrisse), exposés, contracts,
|
|
30
|
+
photos, and any other uploaded files.
|
|
31
|
+
|
|
32
|
+
Use this tool to:
|
|
33
|
+
- See all documents for a property ("Where's the Grundriss?")
|
|
34
|
+
- List a contact's uploaded files
|
|
35
|
+
- Find exposés or contracts for a project
|
|
36
|
+
- Check what's already been uploaded before adding more
|
|
37
|
+
|
|
38
|
+
Filter by exactly one of property_id, project_id, or client_id.`, {
|
|
39
|
+
property_id: z.number().optional()
|
|
40
|
+
.describe("Filter by property ID"),
|
|
41
|
+
project_id: z.number().optional()
|
|
42
|
+
.describe("Filter by project ID"),
|
|
43
|
+
client_id: z.number().optional()
|
|
44
|
+
.describe("Filter by contact ID"),
|
|
45
|
+
sort: z.string().optional()
|
|
46
|
+
.describe("Sort string (e.g. 'created_at,desc')"),
|
|
47
|
+
page: z.number().optional()
|
|
48
|
+
.describe("Page number (default: 1)"),
|
|
49
|
+
per_page: z.number().optional()
|
|
50
|
+
.describe("Results per page (default: 25)"),
|
|
51
|
+
}, async (args) => {
|
|
52
|
+
try {
|
|
53
|
+
const res = await client.get("/documents", { params: args });
|
|
54
|
+
if (!res.data || res.data.length === 0) {
|
|
55
|
+
return textResult("No documents found.");
|
|
56
|
+
}
|
|
57
|
+
const header = res.meta?.total_count !== undefined
|
|
58
|
+
? `Found ${res.meta.total_count} documents (showing ${res.data.length}):\n\n`
|
|
59
|
+
: `Found ${res.data.length} documents:\n\n`;
|
|
60
|
+
const formatted = res.data.map(formatDocument).join("\n\n---\n\n");
|
|
61
|
+
return textResult(header + formatted);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
return errorResult("Document", err);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
// ── upload_document ─────────────────────────────────────────────
|
|
68
|
+
server.tool("upload_document", `Upload a document to a property, project, or contact in Propstack.
|
|
69
|
+
|
|
70
|
+
The doc field must be a base64 data URI, e.g.:
|
|
71
|
+
"data:application/pdf;base64,JVBERi0xLjQ..."
|
|
72
|
+
"data:image/png;base64,iVBORw0KGgo..."
|
|
73
|
+
|
|
74
|
+
Attach to exactly one entity: property_id, project_id, or client_id.
|
|
75
|
+
|
|
76
|
+
Use the boolean flags to classify the document:
|
|
77
|
+
- is_floorplan: Mark as a floor plan (Grundriss)
|
|
78
|
+
- is_exposee: Mark as an exposé document
|
|
79
|
+
- is_private: Hide from public/portal views
|
|
80
|
+
- on_landing_page: Show on the property landing page`, {
|
|
81
|
+
title: z.string()
|
|
82
|
+
.describe("Document title"),
|
|
83
|
+
doc: z.string()
|
|
84
|
+
.describe("Base64 data URI (e.g. 'data:application/pdf;base64,...')"),
|
|
85
|
+
property_id: z.number().optional()
|
|
86
|
+
.describe("Attach to this property"),
|
|
87
|
+
project_id: z.number().optional()
|
|
88
|
+
.describe("Attach to this project"),
|
|
89
|
+
client_id: z.number().optional()
|
|
90
|
+
.describe("Attach to this contact"),
|
|
91
|
+
is_private: z.boolean().optional()
|
|
92
|
+
.describe("Mark as private (hidden from portals)"),
|
|
93
|
+
is_floorplan: z.boolean().optional()
|
|
94
|
+
.describe("Mark as floor plan (Grundriss)"),
|
|
95
|
+
is_exposee: z.boolean().optional()
|
|
96
|
+
.describe("Mark as exposé document"),
|
|
97
|
+
on_landing_page: z.boolean().optional()
|
|
98
|
+
.describe("Show on property landing page"),
|
|
99
|
+
}, async (args) => {
|
|
100
|
+
try {
|
|
101
|
+
const document = await client.post("/documents", { body: { document: stripUndefined(args) } });
|
|
102
|
+
return textResult(`Document uploaded successfully.\n\n${formatDocument(document)}`);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
return errorResult("Document", err);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=documents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documents.js","sourceRoot":"","sources":["../../src/tools/documents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emails.d.ts","sourceRoot":"","sources":["../../src/tools/emails.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAkC9D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAmGnF"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { textResult, errorResult, fmt, stripUndefined } from "./helpers.js";
|
|
3
|
+
// ── Response formatting ──────────────────────────────────────────────
|
|
4
|
+
function formatEmail(e) {
|
|
5
|
+
const lines = [
|
|
6
|
+
`**${fmt(e.subject, "No subject")}** (ID: ${e.id})`,
|
|
7
|
+
`From: ${fmt(e.from)}`,
|
|
8
|
+
`To: ${e.to?.join(", ") ?? "none"}`,
|
|
9
|
+
e.cc?.length ? `CC: ${e.cc.join(", ")}` : null,
|
|
10
|
+
e.bcc?.length ? `BCC: ${e.bcc.join(", ")}` : null,
|
|
11
|
+
`Broker ID: ${fmt(e.broker_id)}`,
|
|
12
|
+
e.snippet_id ? `Template ID: ${e.snippet_id}` : null,
|
|
13
|
+
`Read: ${e.read ? "yes" : "no"}`,
|
|
14
|
+
`Archived: ${e.archived ? "yes" : "no"}`,
|
|
15
|
+
e.message_category_id ? `Category ID: ${e.message_category_id}` : null,
|
|
16
|
+
];
|
|
17
|
+
if (e.client_ids?.length)
|
|
18
|
+
lines.push(`Contact IDs: ${e.client_ids.join(", ")}`);
|
|
19
|
+
if (e.property_ids?.length)
|
|
20
|
+
lines.push(`Property IDs: ${e.property_ids.join(", ")}`);
|
|
21
|
+
if (e.project_ids?.length)
|
|
22
|
+
lines.push(`Project IDs: ${e.project_ids.join(", ")}`);
|
|
23
|
+
if (e.attachments?.length) {
|
|
24
|
+
lines.push(`Attachments: ${e.attachments.map((a) => fmt(a.name, "unnamed")).join(", ")}`);
|
|
25
|
+
}
|
|
26
|
+
lines.push(`Date: ${fmt(e.created_at)}`);
|
|
27
|
+
return lines.filter(Boolean).join("\n");
|
|
28
|
+
}
|
|
29
|
+
// ── Tool registration ────────────────────────────────────────────────
|
|
30
|
+
export function registerEmailTools(server, client) {
|
|
31
|
+
// ── send_email ──────────────────────────────────────────────────
|
|
32
|
+
server.tool("send_email", `Send an email using a Propstack email template (snippet).
|
|
33
|
+
|
|
34
|
+
Propstack sends emails through connected broker email accounts. The
|
|
35
|
+
broker_id determines which account sends the email. The snippet_id
|
|
36
|
+
selects the email template to use.
|
|
37
|
+
|
|
38
|
+
Use this tool to:
|
|
39
|
+
- Send an exposé to an interested contact
|
|
40
|
+
- Send a follow-up email after a viewing
|
|
41
|
+
- Send a confirmation or rejection to a lead
|
|
42
|
+
|
|
43
|
+
Link the email to contacts, properties, and projects so it appears
|
|
44
|
+
in the correct CRM activity feeds.
|
|
45
|
+
|
|
46
|
+
Important:
|
|
47
|
+
- broker_id must be a broker with a connected email account
|
|
48
|
+
- snippet_id is the email template ID — the template may contain
|
|
49
|
+
merge fields that Propstack fills automatically (contact name,
|
|
50
|
+
property details, etc.)
|
|
51
|
+
- to[] are the recipient email addresses
|
|
52
|
+
- cc[] are optional CC recipients`, {
|
|
53
|
+
broker_id: z.number()
|
|
54
|
+
.describe("Sender broker ID (must have connected email account)"),
|
|
55
|
+
to: z.array(z.string())
|
|
56
|
+
.describe("Recipient email addresses"),
|
|
57
|
+
snippet_id: z.number()
|
|
58
|
+
.describe("Email template (snippet) ID"),
|
|
59
|
+
cc: z.array(z.string()).optional()
|
|
60
|
+
.describe("CC recipient email addresses"),
|
|
61
|
+
client_ids: z.array(z.number()).optional()
|
|
62
|
+
.describe("Contact IDs to link this email to"),
|
|
63
|
+
property_ids: z.array(z.number()).optional()
|
|
64
|
+
.describe("Property IDs to link this email to"),
|
|
65
|
+
project_ids: z.array(z.number()).optional()
|
|
66
|
+
.describe("Project IDs to link this email to"),
|
|
67
|
+
}, async (args) => {
|
|
68
|
+
try {
|
|
69
|
+
const email = await client.post("/messages", { body: { message: stripUndefined(args) } });
|
|
70
|
+
return textResult(`Email sent successfully.\n\n${formatEmail(email)}`);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
return errorResult("Email", err);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// ── update_email ────────────────────────────────────────────────
|
|
77
|
+
server.tool("update_email", `Update an email in Propstack.
|
|
78
|
+
|
|
79
|
+
Use this tool to:
|
|
80
|
+
- Mark an email as read or unread
|
|
81
|
+
- Archive an email
|
|
82
|
+
- Categorize an email (set message_category_id)
|
|
83
|
+
- Link an email to contacts, properties, or projects
|
|
84
|
+
|
|
85
|
+
Only provide the fields you want to change.`, {
|
|
86
|
+
id: z.number()
|
|
87
|
+
.describe("Email/message ID to update"),
|
|
88
|
+
read: z.boolean().optional()
|
|
89
|
+
.describe("Mark as read (true) or unread (false)"),
|
|
90
|
+
archived: z.boolean().optional()
|
|
91
|
+
.describe("Archive (true) or unarchive (false)"),
|
|
92
|
+
message_category_id: z.number().optional()
|
|
93
|
+
.describe("Email category ID"),
|
|
94
|
+
client_ids: z.array(z.number()).optional()
|
|
95
|
+
.describe("Contact IDs to link this email to"),
|
|
96
|
+
property_ids: z.array(z.number()).optional()
|
|
97
|
+
.describe("Property IDs to link this email to"),
|
|
98
|
+
project_ids: z.array(z.number()).optional()
|
|
99
|
+
.describe("Project IDs to link this email to"),
|
|
100
|
+
}, async (args) => {
|
|
101
|
+
try {
|
|
102
|
+
const { id, ...fields } = args;
|
|
103
|
+
const email = await client.put(`/messages/${id}`, { body: { message: stripUndefined(fields) } });
|
|
104
|
+
return textResult(`Email updated successfully.\n\n${formatEmail(email)}`);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
return errorResult("Email", err);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=emails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emails.js","sourceRoot":"","sources":["../../src/tools/emails.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export declare function textResult(text: string): {
|
|
2
|
+
content: {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
}[];
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Format any error into a user-friendly string.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatError(err: unknown): string;
|
|
11
|
+
export declare function errorResult(entity: string, err: unknown): {
|
|
12
|
+
content: {
|
|
13
|
+
type: "text";
|
|
14
|
+
text: string;
|
|
15
|
+
}[];
|
|
16
|
+
} | {
|
|
17
|
+
content: {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}[];
|
|
21
|
+
isError: true;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Propstack API with new=1/expand=1 returns nested objects like { value: X } or
|
|
25
|
+
* { value: X, pretty_value: Y }. Unwrap to the underlying primitive for display.
|
|
26
|
+
*/
|
|
27
|
+
export declare function unwrapPropstackValue(val: unknown): unknown;
|
|
28
|
+
export declare function fmt(value: unknown, fallback?: string): string;
|
|
29
|
+
/** Unwrap and coerce to number for price/area formatting. */
|
|
30
|
+
export declare function unwrapNumber(val: unknown): number | null;
|
|
31
|
+
export declare function fmtPrice(value: unknown): string;
|
|
32
|
+
export declare function fmtArea(value: unknown, unit?: string): string;
|
|
33
|
+
export declare function fmtNested(obj: unknown, key: string, fallback?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Remove keys with undefined values from an object so we don't send
|
|
36
|
+
* nulls to the API when optional fields are omitted.
|
|
37
|
+
*/
|
|
38
|
+
export declare function stripUndefined<T extends Record<string, unknown>>(obj: T): Partial<T>;
|
|
39
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM;;;;;EAEtC;AAiCD;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAyBhD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO;;;;;;;;;;;EAwBvD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAY1D;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAS,GAAG,MAAM,CAK7D;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAQxD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAI/C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAO,GAAG,MAAM,CAI3D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAS,GAAG,MAAM,CAI9E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQpF"}
|