
Security News
PHP Foundation Says Chainguard Broke Security Embargo Ahead of Emergency Patches
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.
callerkit-mcp
Advanced tools
An MCP server that lets AI assistants and agents (Claude, Cursor, custom agents) use the CallerKit caller-ID / phone-lookup API.
| Tool | What it does | Cost |
|---|---|---|
callerkit_lookup_phone | Name, aliases (with report counts), spam count, emails, socials, carrier, line type, country for one number | 1 credit if a name is found |
callerkit_assess_number_risk | 0-100 risk score + level + reasons; optional expected_name match (Latin and Arabic aware) | 1 credit if a name is found |
callerkit_search_by_name | Numbers matching a name in a country, paged (paid plan) | 1 credit / result |
callerkit_search_by_email | Details matching an email, max 10 (paid plan) | 1 credit / result |
callerkit_bulk_lookup | Up to CALLERKIT_MAX_BULK (default 25) numbers, deduped, compact rows with risk level | 1 credit / number found |
All tools are annotated read-only / idempotent. "No record" is always reported as unknown, never as "safe".
Phone numbers can be E.164 (+971501234567) or national with a country (0501234567, AE); the
server derives the country_code the API needs with libphonenumber.
This lives in the backend repo, and mirrors it in two files:
src/endpoints.ts: paths and request bodies (routes/api.php, app/Http/Requests/Api/*Request.php).src/normalize.ts: the {code, status, msg, data: {numbers: {data: [...]}}} envelope and NumberResource rows.Error mapping (src/client.ts): 401 bad key, 403 blocked / no plan / paid-only (with upgrade_url),
422 validation, 429 with Retry-After = throttled (retried), 429 without = credits used up (not retried;
bulk stops). Change these files together with the backend.
Listed as com.caller-kit/callerkit-mcp (server.json; mcpName in package.json must match).
Namespace ownership is proven by public/.well-known/mcp-registry-auth in the backend (HTTP auth, Ed25519).
To release: bump version in package.json, src/version.ts and both versions in server.json, npm publish,
then mcp-publisher login http --domain caller-kit.com --private-key … and mcp-publisher publish.
import { createCallerKitServer, loadConfig } from "callerkit-mcp" gives an McpServer bound to one API key, to
serve over any transport. The hosted server in ../mcp-hosted uses this. The callerkit-mcp binary is the CLI.
npm install
npm run build
cp .env.example .env # then export the variables, or pass them in your client config
npm test # 25 end-to-end checks against a mock API, over stdio and HTTP
npm run test:live # contract check against the real backend (default: local php artisan serve)
Required: CALLERKIT_API_KEY. Optional: CALLERKIT_BASE_URL (default https://caller-kit.com; must be https://, except localhost).
CALLERKIT_INCLUDE_RAW=true also returns the raw API response, for debugging.
test:live uses the LocalDevSeeder key and sample numbers by default; override with CALLERKIT_LIVE_URL,
CALLERKIT_LIVE_KEY, CALLERKIT_LIVE_PHONE. Name/email search need Sphinx, so they only run with
CALLERKIT_LIVE_SEARCH=1. Against production it spends real credits.
{
"mcpServers": {
"callerkit": {
"command": "node",
"args": ["/absolute/path/to/caller-kit-backend/mcp/dist/index.js"],
"env": {
"CALLERKIT_API_KEY": "…",
"CALLERKIT_BASE_URL": "https://…"
}
}
}
}
claude mcp add callerkit \
--env CALLERKIT_API_KEY=… --env CALLERKIT_BASE_URL=https://… \
-- node /absolute/path/to/caller-kit-backend/mcp/dist/index.js
PORT=3000 HOST=127.0.0.1 node dist/index.js --http
# POST http://127.0.0.1:3000/mcp header: Api-key: <the CALLER'S own CallerKit key>
Stateless, one server instance per request, and every caller brings their own CallerKit key, so the server holds no secrets and one customer can never spend another's credits. Put it behind TLS (Caddy/nginx/Cloudflare) and add rate limiting at the edge. It binds to loopback by default; only set HOST=0.0.0.0 behind a proxy.
1. Design tools around the agent's job, not around your endpoints. CallerKit has three raw endpoints. The most useful tool, assess_number_risk, isn't an endpoint at all: it composes a lookup with a scoring heuristic and answers "should I ship this order?". Fewer, outcome-shaped tools beat a 1:1 API wrapper.
2. The description is the product. The model decides whether and how to call a tool from its name, description and schema alone. Say what it returns, when to use it, what it costs, input format (E.164, with an example), and limits. Prefix names (callerkit_…) so they don't collide with other servers.
3. Errors are part of the conversation. Return isError: true with a message the model can act on ("not valid E.164, e.g. +971…", "Pro plan required", "config problem, retrying won't help") instead of throwing. A thrown exception becomes an opaque protocol error.
4. In stdio mode, stdout belongs to the protocol. A stray console.log corrupts the stream. Log to stderr only. Mask personal data in logs (phones are logged as +971***67).
5. Validate at the edge, be lenient where it helps. Strict schema on the things that must be right (an email must be an email), but in bulk input I accept junk entries and report them as invalid rather than rejecting the whole batch. My own test caught me being too strict here.
6. Make cost and blast radius visible. The API charges per result, and an agent can loop. So: credit cost is in every description, bulk is capped, duplicates are removed, and bulk stops early on auth/plan errors instead of burning requests (verified: ≤ concurrency requests go out after a bad key or exhausted credits).
7. Treat the agent as an untrusted caller of sensitive data. This API returns personal data, and agents make bulk profiling easy. The descriptions state the legitimate-use boundary, name/email search is Pro-gated by your API, and bulk is capped. Consider adding your own audit log and per-key daily limits server-side.
8. Be honest in derived outputs. The risk score is a transparent, deterministic heuristic with reasons, and "no record" yields score: null, level: unknown. Models over-trust confident-looking numbers, so don't let a missing record read as "safe".
9. Isolate the contract. All API shapes sit in endpoints.ts and normalize.ts; the rest of the server is tested against a mock, and test:live checks the mock's assumptions against the real backend. The first version guessed the shapes and got the path, body, envelope, not-found and 429 semantics wrong, which only reading the backend revealed.
10. Test through a real MCP client, not just unit tests. npm test spawns the built server and drives it with the SDK's client over stdio and HTTP. That caught a logging bug (metadata overwrote the log level) and the over-strict bulk schema, neither of which unit tests of the pure functions would have shown.
Transport choice: stdio for local tools (Claude Desktop / Code), Streamable HTTP for anything you host. Prefer stateless HTTP unless you truly need server-initiated messages or per-session state.
npx callerkit-mcp) and list on MCP registries/directories, since discovery is the main channel.FAQs
MCP server for the CallerKit caller ID / phone lookup API
The npm package callerkit-mcp receives a total of 29 weekly downloads. As such, callerkit-mcp popularity was classified as not popular.
We found that callerkit-mcp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.

Threat Research
/Security News
A supply chain attack compromised LiteLLM 1.107.0 on PyPI and Docker, spreading malware that steals cloud credentials, developer secrets, and AI provider keys.