Skip to content

Commit b11dea8

Browse files
committed
chore(skill): sync MCP reference into zaileys-official plugin copy
1 parent d88f272 commit b11dea8

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

plugins/zaileys-official/skills/assist/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ knowledge). Sibling focused skills exist for explicit invocation, but you can do
2828
| **Review/audit** ("review", "cek kode", "is this correct", before shipping) | Check against best practices + anti-patterns + ban-safety; report findings + fixes | [references/pitfalls.md](references/pitfalls.md) |
2929
| **Implement a feature** (send X, buttons, AIRich, command, broadcast, storage) | Use the right API + a recipe; apply golden rules | [references/api.md](references/api.md), [references/recipes.md](references/recipes.md) |
3030
| **Explain/choose** ("how does X work", "which adapter", "qr vs pairing") | Answer from the references; show a minimal example | all references |
31+
| **AI bot + external tools** ("connect MCP", "give the bot tools", scraper catalog, "MCP server", zpi) | Wire MCP server(s) into the LLM call (AI SDK), expose tools via a lazy router | [references/mcp.md](references/mcp.md) |
3132

3233
Default when ambiguous: ask one clarifying question, then proceed. Prefer doing the work
3334
over describing it.
@@ -41,6 +42,7 @@ Read the relevant file before writing or debugging — they contain the verified
4142
- [references/errors.md](references/errors.md) — every error class + `.code`, what it means, and how to fix it. **Read this first when diagnosing an exception.**
4243
- [references/troubleshooting.md](references/troubleshooting.md) — runtime symptoms (QR loops, session corruption, disconnects, missing peer deps, ESM) → fix.
4344
- [references/pitfalls.md](references/pitfalls.md) — common mistakes & anti-patterns → the correct way. **Read this when reviewing code.**
45+
- [references/mcp.md](references/mcp.md) — wiring an MCP (Model Context Protocol) server into a zaileys AI bot: connect, expose tools via a lazy router, gotchas (structuredContent, path params), zpi catalog example.
4446

4547
For exhaustive detail, the full docs are one file: <https://zeative.github.io/zaileys/llms-full.txt>.
4648

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# MCP integration — wiring a Model Context Protocol server into a zaileys AI bot
2+
3+
zaileys is the WhatsApp transport. When you build an **AI bot** on top of it (LLM replies via the
4+
Vercel AI SDK), you can give the model extra capabilities by connecting **MCP (Model Context
5+
Protocol)** servers — e.g. a scraper catalog like zpi (`mcp.zpi.web.id`). This recipe shows the
6+
pattern: connect an MCP server, expose its tools to the model, and keep the per-turn tool payload
7+
small with a lazy router.
8+
9+
> Scope: this is **app-level** (AI SDK + MCP SDK), not a zaileys API. zaileys only handles
10+
> sending/receiving the WhatsApp messages; the MCP tools are wired into your LLM call.
11+
12+
## Concepts (quick)
13+
14+
- **MCP** exposes **tools** (callable functions w/ JSON Schema), **resources**, and **prompts**.
15+
- **Transport:** `stdio` (local process), `SSE` (legacy remote), `Streamable HTTP` (modern remote, POST + optional SSE stream). Remote catalogs like zpi use Streamable HTTP.
16+
- **Handshake (Streamable HTTP):** POST `initialize` → server returns `protocolVersion`/`capabilities`/`serverInfo` + `mcp-session-id` header → client sends `notifications/initialized` → then `tools/list` / `tools/call`. `Accept` header must be `application/json, text/event-stream`.
17+
- **Auth:** header (`Authorization: Bearer <key>` or a custom header). Some clients are OAuth-only and need the `mcp-remote` bridge.
18+
19+
## Install
20+
21+
```bash
22+
npm i @modelcontextprotocol/sdk ai
23+
```
24+
25+
## Connect + expose tools to the model
26+
27+
```ts
28+
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
29+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
30+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'
31+
import { dynamicTool, jsonSchema, type ToolSet } from 'ai'
32+
33+
export async function loadMcpTools(url: string, headers: Record<string, string>): Promise<ToolSet> {
34+
const client = new Client({ name: 'my-bot', version: '1.0.0' })
35+
const requestInit = { headers }
36+
try {
37+
await client.connect(new StreamableHTTPClientTransport(new URL(url), { requestInit }))
38+
} catch {
39+
await client.connect(new SSEClientTransport(new URL(url), { requestInit })) // fallback
40+
}
41+
42+
const { tools } = await client.listTools()
43+
const out: ToolSet = {}
44+
for (const t of tools) {
45+
out[t.name] = dynamicTool({
46+
description: t.description ?? t.name,
47+
inputSchema: jsonSchema(t.inputSchema as Parameters<typeof jsonSchema>[0]),
48+
execute: async (args) => {
49+
const res = await client.callTool({ name: t.name, arguments: args as Record<string, unknown> })
50+
// IMPORTANT: real data is often in structuredContent, not content[].text
51+
const structured = (res as { structuredContent?: unknown }).structuredContent
52+
const text = (res.content as { type: string; text?: string }[])
53+
.filter((c) => c.type === 'text').map((c) => c.text ?? '').join('\n').trim()
54+
return structured != null ? { summary: text, data: structured } : (text || '(empty)')
55+
},
56+
})
57+
}
58+
return out
59+
}
60+
```
61+
62+
Then pass them into your model call alongside zaileys:
63+
64+
```ts
65+
import { streamText } from 'ai'
66+
import { Client as Zaileys } from 'zaileys'
67+
68+
const mcpTools = await loadMcpTools('https://mcp.zpi.web.id/mcp', {
69+
Authorization: `Bearer ${process.env.ZPI_API_KEY}`,
70+
})
71+
72+
const wa = new Zaileys({ /* ...zaileys options... */ })
73+
wa.on('messages', async (ctx) => {
74+
const res = streamText({ model, system, messages, tools: { ...mcpTools /*, ...yourTools */ } })
75+
// stream res.text back via the zaileys send builder
76+
// await wa.send(ctx.roomId).text(finalText)
77+
})
78+
```
79+
80+
## Gotchas (learned in production)
81+
82+
1. **Read `structuredContent`.** Many servers put the actual payload in `result.structuredContent`; `content[].text` may be just a summary (e.g. `"Success: ..."`). Returning only the text starves the model of data.
83+
2. **Path params go in `params`.** For endpoints like `/:username`, pass `params: { username }` to the server's run/call tool — don't bake the value into the endpoint string.
84+
3. **Don't dump every tool as always-active.** A catalog can expose dozens of tools. Use a **lazy router**: keep tools defined but inactive, expose one `find_tools(query)` meta-tool that ranks them (semantic + keyword) and activates only the matches for the next step. Mark a few "primary" tools always-active.
85+
4. **find_tools ranking: merge semantic + keyword.** Pure embedding similarity misses exact-name hits (query `"instagram"` vs a generic tool description can score < 0.3). Union keyword matches so exact hits always surface.
86+
5. **Keep reflexive/expensive tools lazy.** A model will reach for `web_search` first if it's always on. Make it discoverable instead, so cheaper/primary tools win by default.
87+
6. **Accept header + session.** Streamable HTTP needs `Accept: application/json, text/event-stream` and you must carry the `mcp-session-id` from `initialize` on subsequent calls.
88+
89+
## Example: zpi scraper catalog
90+
91+
- Endpoint `https://mcp.zpi.web.id/mcp` (Streamable HTTP), auth `Authorization: Bearer <key>`.
92+
- Tools: `search_scrapers`, `list_categories`, `get_scraper_schema`, `run_scraper`, `get_account`, `get_usage`, `bulk_submit`, `bulk_status`.
93+
- Flow (2 hop): `search_scrapers` (natural-language query) → `run_scraper` (skip schema when params are obvious).
94+
- Public scraper page URL: `https://zpi.web.id/api/<category>/<slug>`.
95+
96+
## Sources
97+
98+
- MCP docs: <https://modelcontextprotocol.io>
99+
- MCP TypeScript SDK: <https://github.com/modelcontextprotocol/typescript-sdk>
100+
- Vercel AI SDK tools: <https://ai-sdk.dev/docs>

0 commit comments

Comments
 (0)