@spekoai/mcp-calls 0.4.0 → 0.4.3
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 +1 -1
- package/dist/index.js +109 -43
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/skills/speko-calls/SKILL.md +70 -49
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spekoai/mcp-calls",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Place real, disclosed phone calls to businesses straight from your coding agent — the Speko \"AI calls for devs\" MCP. Single self-contained package: `npx @spekoai/mcp-calls init` to set up.",
|
|
5
5
|
"mcpName": "ai.speko/mcp-calls",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
"title": "Speko — AI Calls for Devs",
|
|
5
5
|
"description": "Place real, disclosed outbound phone calls to businesses straight from your coding agent.",
|
|
6
6
|
"repository": { "url": "https://github.com/SpekoAI/mcp-dev-calls", "source": "github" },
|
|
7
|
-
"version": "0.4.
|
|
7
|
+
"version": "0.4.3",
|
|
8
8
|
"websiteUrl": "https://speko.ai",
|
|
9
9
|
"packages": [
|
|
10
10
|
{
|
|
11
11
|
"registryType": "npm",
|
|
12
12
|
"identifier": "@spekoai/mcp-calls",
|
|
13
|
-
"version": "0.4.
|
|
13
|
+
"version": "0.4.3",
|
|
14
14
|
"transport": { "type": "stdio" },
|
|
15
15
|
"environmentVariables": [
|
|
16
16
|
{
|
|
@@ -1,67 +1,88 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: speko-calls
|
|
3
3
|
description: >-
|
|
4
|
-
Use when the user wants to place a REAL outbound phone call
|
|
5
|
-
|
|
6
|
-
hours/availability/pricing, or chase an order.
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
Use when the user wants to place a REAL outbound phone call via the Speko Calls MCP — e.g.
|
|
5
|
+
"call <place> and ask <question>", "find the best <X> near me and call them", book a
|
|
6
|
+
reservation, check hours/availability/pricing, or place/chase an order. Covers calling a
|
|
7
|
+
number you have or found via web search (call_number) and Speko's verified business lookup
|
|
8
|
+
(lookup_business → make_call), the mandatory AI disclosure, the quiet-hours + no-spam rails,
|
|
9
|
+
and reporting the call OUTCOME honestly.
|
|
9
10
|
---
|
|
10
11
|
|
|
11
|
-
# Speko Calls — placing real, disclosed
|
|
12
|
+
# Speko Calls — placing real, disclosed phone calls
|
|
12
13
|
|
|
13
|
-
The Speko Calls MCP places **real, disclosed** outbound phone calls
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
The Speko Calls MCP places **real, disclosed** outbound phone calls and returns the result as
|
|
15
|
+
text. Every call opens with a non-removable AI disclosure — the callee hears
|
|
16
|
+
*"Hey! Quick heads up — I'm \<your-name\>'s AI assistant, \<your-name\> asked me to give you a
|
|
17
|
+
call…"* before anything else.
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
If the number's region isn't auto-recognized for quiet-hours, also pass `utc_offset_minutes`
|
|
26
|
-
(e.g. -300 US Eastern) — you know the business's city from your search.
|
|
27
|
-
3. **`make_call(dial_token, objective, caller_name, context?)`** — places the disclosed
|
|
28
|
-
call, waits while it rings, returns the `OUTCOME:` line + transcript.
|
|
19
|
+
There are **two ways to dial**:
|
|
20
|
+
- **`call_number`** — dial a number you already have, or one you found via web search. Works
|
|
21
|
+
with just the user's Speko key, no extra setup. **This is the hero path for "find a place and
|
|
22
|
+
call it."**
|
|
23
|
+
- **`lookup_business` → `make_call`** — let Speko find the business in a directory and
|
|
24
|
+
carrier-verify it's a real business line, then dial. Use when you want that verification (the
|
|
25
|
+
server must have directory/carrier keys configured).
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
## Find the number yourself (the hero flow)
|
|
28
|
+
When the user names a *kind* of place ("the best taco spot in the Bay Area"), don't ask them
|
|
29
|
+
for a number — find it and call it. **Be decisive — don't stall the user with options.**
|
|
30
|
+
1. **Web-search** and pick the SINGLE best match; don't make the user choose from a list. Read
|
|
31
|
+
its official site/listing for the full phone number and its city.
|
|
32
|
+
2. **`call_number(phone_number=<+E.164>, objective, caller_name)`** places the disclosed call.
|
|
33
|
+
Use a full international number with a leading `+` and country code (`+14152857117`, not
|
|
34
|
+
`(415) 285-7117`). The destination timezone auto-derives from common area codes; if the tool
|
|
35
|
+
says it couldn't determine the timezone (an unusual area code, or a toll-free
|
|
36
|
+
800/888/877/866 number), re-run with `utc_offset_minutes` for the business's city
|
|
37
|
+
(US Pacific is `-420` in summer / `-480` in winter, US Eastern `-240`/`-300`, UK `+60`/`0`).
|
|
38
|
+
3. One quick inline confirm ("calling La Taqueria, +1 415-285-7117, to ask if they have carnitas
|
|
39
|
+
— go?"), then dial. A call is a real-world action, so keep the gate to a single yes/no.
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
Example: *"find the best taco place in the Bay Area and ask if they're open and have carnitas"*
|
|
42
|
+
→ search → pick La Taqueria → `call_number(...)` → relay the `OUTCOME`.
|
|
43
|
+
|
|
44
|
+
## Writing the objective
|
|
45
|
+
One plain, transactional goal in everyday words:
|
|
46
|
+
- **reservation:** *"Ask if there's a table for 4 at 8pm tonight and book it under John."*
|
|
47
|
+
- **order:** *"Order 2 carnitas tacos and a Coke Zero for pickup, and ask when it'll be ready."*
|
|
48
|
+
- **info:** *"Ask if they're open now and how long the wait is for a table for 2."*
|
|
49
|
+
|
|
50
|
+
Pass the user's name as `caller_name` (the disclosure says *"I'm \<caller_name\>'s AI assistant"*).
|
|
51
|
+
Avoid words the no-spam screen refuses — they match as substrings (e.g. "promot" catches
|
|
52
|
+
"promotion"): *sell, sales pitch, promote, discount, sponsor, advertise, marketing, survey,
|
|
53
|
+
donate, fundraise, vote, campaign, debt, warranty, crypto, investment.* Just say it plainly
|
|
54
|
+
("order…", "ask if…", "book…", "check the price of…"). ("deal" is fine.)
|
|
55
|
+
|
|
56
|
+
## The verified directory path — `lookup_business` → `make_call`
|
|
57
|
+
1. **`check_call_readiness()`** — read-only preflight (auth, credit, outbound caller-ID). Run
|
|
58
|
+
first if unsure the account can dial. Never dials.
|
|
59
|
+
2. **`lookup_business(name, location?, phone_number?, utc_offset_minutes?)`** — resolves the
|
|
60
|
+
business to candidates, each with a **signed, single-use `dial_token`** (the only thing that
|
|
61
|
+
can authorize `make_call`). Needs the server's directory/carrier keys; without them, use
|
|
62
|
+
`call_number` with a number you found instead.
|
|
63
|
+
3. **`make_call(dial_token, objective, caller_name, context?)`** — places the disclosed call,
|
|
64
|
+
waits while it rings, and returns the `OUTCOME:` line + transcript.
|
|
38
65
|
|
|
39
66
|
## The rails (enforced server-side — you cannot override them)
|
|
40
|
-
- **Business lines only** — mobiles are blocked (carrier line-type check).
|
|
41
|
-
- **Transactional objectives only** — reservations, availability, hours, pricing, order
|
|
42
|
-
status. **Refused:** selling, promotion, surveys, fundraising, political campaigning.
|
|
43
|
-
- **Quiet hours** — 08:00–21:00 in the destination's local time (fail-closed if unknown).
|
|
44
67
|
- **AI disclosure** — hard-coded; cannot be removed or reworded.
|
|
68
|
+
- **Transactional objectives only** — reservations, availability, hours, pricing, orders.
|
|
69
|
+
**Refused:** selling, promotion, surveys, fundraising, political campaigning.
|
|
70
|
+
- **Quiet hours** — 08:00–21:00 in the destination's local time; calls outside are rejected
|
|
71
|
+
(fail-closed if the timezone is unknown — pass `utc_offset_minutes`).
|
|
72
|
+
- **Business-line verification** applies on the `lookup_business` path (mobiles blocked there).
|
|
45
73
|
|
|
46
|
-
If an objective trips a rail,
|
|
47
|
-
|
|
74
|
+
If an objective trips a rail, the tool returns a rejection with a reason. Fix the objective (or
|
|
75
|
+
pass `utc_offset_minutes`) and retry, or tell the user it isn't allowed.
|
|
48
76
|
|
|
49
77
|
## Reading the result — honestly
|
|
50
|
-
- `connected` / `answered` are reported truthfully. If the platform never put a real call
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Relay it plainly and offer the transcript.
|
|
56
|
-
|
|
57
|
-
## Personal calls — `call_number`
|
|
58
|
-
If the user wants to call a **specific number they give you** (e.g. a friend), use
|
|
59
|
-
`call_number(phone_number, objective, caller_name, recipient_name?)` — not the business
|
|
60
|
-
flow. It works by default. Mobiles are allowed here; the AI disclosure, quiet hours, and
|
|
61
|
-
no-spam screen still apply. Only ever call a number the user **explicitly provides and has
|
|
62
|
-
consent to call** — never one you guessed. For businesses, use `lookup_business` instead.
|
|
78
|
+
- `connected` / `answered` are reported truthfully. If the platform never put a real call on
|
|
79
|
+
the wire, it returns **`not_connected`** — do **not** report that as success; run
|
|
80
|
+
`check_call_readiness` and tell the user the deployment's outbound trunk/caller-ID may need setup.
|
|
81
|
+
- The `OUTCOME:` line is the answer (e.g. *"table for 4 at 8pm, booked under John"*). Relay it
|
|
82
|
+
plainly and offer the transcript.
|
|
63
83
|
|
|
64
84
|
## Don't
|
|
65
|
-
- Don't invent or guess phone numbers —
|
|
66
|
-
|
|
85
|
+
- Don't invent or guess phone numbers — only dial a number the user gave you or one you found
|
|
86
|
+
from the business's own official listing.
|
|
87
|
+
- Don't retry after a pre-dial rejection without fixing the objective/timezone first.
|
|
67
88
|
- Don't promise a call will connect — report what actually happened.
|