tutti-mcp 0.1.0 → 0.1.1
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 +74 -91
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,54 +1,37 @@
|
|
|
1
|
-
# tutti
|
|
1
|
+
# 🇨🇭 tutti MCP
|
|
2
2
|
|
|
3
|
-
> Search tutti.ch Swiss classifieds from
|
|
3
|
+
> Search tutti.ch Swiss classifieds from your AI agent or the command line — **anonymous and read-only by design**.
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/tutti-mcp)
|
|
6
|
+
[](https://www.npmjs.com/package/tutti-mcp)
|
|
7
|
+
[](./LICENSE)
|
|
5
8
|
[](https://modelcontextprotocol.io)
|
|
6
|
-
[](./LICENSE)
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- `tutti-mcp`: MCP stdio server for Claude, Codex, Cursor, and other MCP-capable clients
|
|
11
|
-
- `tutti`: CLI with matching subcommands and JSON output
|
|
10
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server that gives any MCP-capable agent (Claude, Codex, Cursor, …) the ability to search listings on [`tutti.ch`](https://www.tutti.ch), fetch listing details, browse categories, and resolve Swiss localities. The same search core also ships as a `tutti` CLI with JSON output — handy for scripts and shell-based agents.
|
|
12
11
|
|
|
13
12
|
Ask your agent things like:
|
|
14
13
|
|
|
15
|
-
- "Search tutti for a bike under 300 CHF in Zürich."
|
|
16
|
-
- "Find free sofas
|
|
17
|
-
- "Get details for tutti listing 81828298."
|
|
18
|
-
- "
|
|
14
|
+
- *"Search tutti for a bike under 300 CHF in Zürich."*
|
|
15
|
+
- *"Find free sofas within 10 km of Bern."*
|
|
16
|
+
- *"Get details for tutti listing 81828298."*
|
|
17
|
+
- *"Which tutti categories are there for furniture?"*
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
**Why read-only?** No login, no messaging, no favorites, no posting, no bulk export. Nothing this server does can touch your account or spam sellers — an agent can browse freely with zero risk. See [Safety model](#safety-model).
|
|
21
20
|
|
|
22
21
|
---
|
|
23
22
|
|
|
24
|
-
## Quick
|
|
25
|
-
|
|
26
|
-
After publishing to npm, run the MCP server directly with `npx`:
|
|
23
|
+
## Quick start
|
|
27
24
|
|
|
28
|
-
```
|
|
25
|
+
```bash
|
|
29
26
|
npx -y tutti-mcp
|
|
30
27
|
```
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```sh
|
|
35
|
-
npx -y -p tutti-mcp tutti search velo --max 300 --limit 5
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Run from a local checkout:
|
|
39
|
-
|
|
40
|
-
```sh
|
|
41
|
-
npm install
|
|
42
|
-
npm run build
|
|
43
|
-
node dist/cli.js search velo --max 300 --limit 5
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
The MCP server speaks stdio, so you normally let your client spawn it.
|
|
29
|
+
The server speaks MCP over stdio, so you normally don't run it by hand — you point your MCP client at it and let the client spawn it. Pick your client below. Requires Node.js 20+.
|
|
47
30
|
|
|
48
31
|
<details>
|
|
49
32
|
<summary><strong>Claude Code</strong></summary>
|
|
50
33
|
|
|
51
|
-
```
|
|
34
|
+
```bash
|
|
52
35
|
claude mcp add tutti -- npx -y tutti-mcp
|
|
53
36
|
```
|
|
54
37
|
|
|
@@ -58,7 +41,7 @@ Restart Claude Code or start a new session after adding the server, then check `
|
|
|
58
41
|
<details>
|
|
59
42
|
<summary><strong>Claude Desktop</strong></summary>
|
|
60
43
|
|
|
61
|
-
Add this to `claude_desktop_config.json
|
|
44
|
+
Add this to your `claude_desktop_config.json` (Settings → Developer → Edit Config):
|
|
62
45
|
|
|
63
46
|
```json
|
|
64
47
|
{
|
|
@@ -77,11 +60,11 @@ Restart Claude Desktop after editing the file.
|
|
|
77
60
|
<details>
|
|
78
61
|
<summary><strong>Codex</strong></summary>
|
|
79
62
|
|
|
80
|
-
```
|
|
63
|
+
```bash
|
|
81
64
|
codex mcp add tutti -- npx -y tutti-mcp
|
|
82
65
|
```
|
|
83
66
|
|
|
84
|
-
Start a new Codex session after adding the server
|
|
67
|
+
Start a **new** Codex session after adding the server (MCP tools aren't injected into a running turn), then confirm with `/mcp` in the TUI.
|
|
85
68
|
</details>
|
|
86
69
|
|
|
87
70
|
<details>
|
|
@@ -101,83 +84,103 @@ Most clients accept a config of this shape:
|
|
|
101
84
|
```
|
|
102
85
|
</details>
|
|
103
86
|
|
|
104
|
-
|
|
87
|
+
No credentials, no configuration — the server works anonymously out of the box.
|
|
105
88
|
|
|
106
89
|
---
|
|
107
90
|
|
|
108
91
|
## Tools
|
|
109
92
|
|
|
110
|
-
All listing URLs use `https://www.tutti.ch/de/vi/<listingID>`. Prices are returned as tutti.ch formats in CHF
|
|
93
|
+
All listing URLs use `https://www.tutti.ch/de/vi/<listingID>`. Prices are returned as tutti.ch formats them, in CHF — for example `"40.-"`.
|
|
111
94
|
|
|
112
95
|
| Tool | Purpose | Auth required | Writes? |
|
|
113
96
|
| --- | --- | :---: | :---: |
|
|
114
|
-
| `search_listings` | Search listings by query, category, price, locality, radius, sort, and cursor. | No | No |
|
|
97
|
+
| `search_listings` | Search listings by query, category, price range, locality, radius, sort, and cursor. | No | No |
|
|
115
98
|
| `get_listing` | Fetch compact detail for one listing id, including description, seller, and up to five image URLs. | No | No |
|
|
116
99
|
| `get_categories` | Return `{ id, label, children }` category nodes; ids are usable as `categoryId`. | No | No |
|
|
117
100
|
| `search_localities` | Search Swiss locality names before using location filters. | No | No |
|
|
118
101
|
|
|
119
|
-
`search_listings` returns `nextCursor` when another page is available
|
|
102
|
+
`search_listings` returns `nextCursor` when another page is available — pass that value back as `cursor` to get the next page.
|
|
120
103
|
|
|
121
104
|
When `location` is provided, the server resolves the text to the top matching Swiss locality. Use `search_localities` first when the place name is ambiguous or misspelled.
|
|
122
105
|
|
|
123
106
|
---
|
|
124
107
|
|
|
125
|
-
## Suggested
|
|
108
|
+
## Suggested workflows
|
|
126
109
|
|
|
127
110
|
**Find listings near a place**
|
|
128
111
|
|
|
129
112
|
1. `search_localities` for the place name if ambiguity matters.
|
|
130
113
|
2. `search_listings` with `location`, optional `radiusKm`, and price filters.
|
|
131
114
|
3. Follow `nextCursor` with another `search_listings` call for page 2.
|
|
132
|
-
4.
|
|
115
|
+
4. `get_listing` for the items that need full details.
|
|
133
116
|
|
|
134
117
|
**Browse by category**
|
|
135
118
|
|
|
136
|
-
1. `get_categories`.
|
|
137
|
-
2. Pick a category `id`.
|
|
138
|
-
3. `search_listings` with `categoryId`.
|
|
119
|
+
1. `get_categories` → 2. pick a category `id` → 3. `search_listings` with `categoryId`.
|
|
139
120
|
|
|
140
|
-
|
|
121
|
+
---
|
|
141
122
|
|
|
142
|
-
|
|
143
|
-
node dist/cli.js search velo --max 300 --limit 5
|
|
144
|
-
node dist/cli.js search velo --location "Zürich" --radius 10 --max 300
|
|
145
|
-
node dist/cli.js get 81828298
|
|
146
|
-
node dist/cli.js categories
|
|
147
|
-
node dist/cli.js localities "zür"
|
|
148
|
-
```
|
|
123
|
+
## CLI
|
|
149
124
|
|
|
150
|
-
|
|
125
|
+
The package also installs a `tutti` bin with subcommands mirroring the MCP tools:
|
|
151
126
|
|
|
152
|
-
```
|
|
127
|
+
```bash
|
|
128
|
+
# One-off with npx
|
|
153
129
|
npx -y -p tutti-mcp tutti search velo --max 300 --limit 5
|
|
154
|
-
npx -y -p tutti-mcp tutti get 81828298
|
|
155
130
|
|
|
156
|
-
|
|
131
|
+
# Or install globally
|
|
132
|
+
npm install -g tutti-mcp
|
|
133
|
+
tutti search velo --location "Zürich" --radius 10 --max 300
|
|
157
134
|
tutti get 81828298
|
|
158
135
|
tutti categories
|
|
159
136
|
tutti localities "zür"
|
|
160
137
|
```
|
|
161
138
|
|
|
162
|
-
|
|
139
|
+
```
|
|
140
|
+
Usage:
|
|
141
|
+
tutti search <query> [--category id] [--min n] [--max n] [--free] [--location name] [--radius km] [--sort timestamp] [--asc] [--cursor c] [--limit n]
|
|
142
|
+
tutti get <listingId>
|
|
143
|
+
tutti categories
|
|
144
|
+
tutti localities <query>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
All commands print JSON to stdout — pretty-printed on a TTY, compact otherwise, so output pipes cleanly into `jq`. Errors go to stderr with exit code 1.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
tutti search sofa --free --location Bern --radius 10 | jq '.listings[].title'
|
|
151
|
+
```
|
|
163
152
|
|
|
164
153
|
---
|
|
165
154
|
|
|
166
|
-
## Safety
|
|
155
|
+
## Safety model
|
|
167
156
|
|
|
168
157
|
This server performs anonymous read-only operations only.
|
|
169
158
|
|
|
170
159
|
- No credentials are accepted or needed.
|
|
171
160
|
- No listings are posted, edited, favorited, or messaged.
|
|
172
161
|
- No HTTP server is exposed; MCP uses stdio only.
|
|
173
|
-
- No raw
|
|
162
|
+
- No raw upstream objects are returned to agents — responses are mapped to compact, project-owned payloads.
|
|
174
163
|
- Upstream requests are throttled to avoid rapid repeated traffic and retried only for transient failures.
|
|
175
164
|
|
|
176
165
|
---
|
|
177
166
|
|
|
178
|
-
##
|
|
167
|
+
## Troubleshooting
|
|
179
168
|
|
|
180
|
-
|
|
169
|
+
| Symptom | Fix |
|
|
170
|
+
| --- | --- |
|
|
171
|
+
| MCP client doesn't show the tools | Restart the client or start a new session so it respawns the server. |
|
|
172
|
+
| `location` matches the wrong place | Run `search_localities` first, then use a more specific place name. |
|
|
173
|
+
| Search fails with a rate-limit message | Wait a few minutes before retrying; the upstream API is behind Cloudflare. |
|
|
174
|
+
| CLI output is one line | Expected when stdout is not a TTY — pipe it through `jq` if needed. |
|
|
175
|
+
| Live tests are skipped | Set `TUTTI_LIVE=1` explicitly. |
|
|
176
|
+
| Inspector command opens a UI instead of running once | Add `--cli` and an explicit `--method`, as shown below. |
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Develop from source
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
git clone https://github.com/domwoe/tutti-mcp.git
|
|
181
184
|
cd tutti-mcp
|
|
182
185
|
npm install
|
|
183
186
|
npm run build
|
|
@@ -185,62 +188,42 @@ npm run build
|
|
|
185
188
|
|
|
186
189
|
Point a client at the built entrypoint:
|
|
187
190
|
|
|
188
|
-
```
|
|
191
|
+
```bash
|
|
189
192
|
claude mcp add tutti -- node /absolute/path/to/tutti-mcp/dist/mcp.js
|
|
190
193
|
```
|
|
191
194
|
|
|
192
|
-
Before publishing:
|
|
193
|
-
|
|
194
|
-
```sh
|
|
195
|
-
npm pack --dry-run
|
|
196
|
-
npm publish
|
|
197
|
-
```
|
|
198
|
-
|
|
199
195
|
### Verification
|
|
200
196
|
|
|
201
|
-
```
|
|
197
|
+
```bash
|
|
202
198
|
npm run typecheck
|
|
203
199
|
npm test
|
|
204
200
|
npm run build
|
|
205
201
|
```
|
|
206
202
|
|
|
207
|
-
Live smoke tests are skipped by default:
|
|
203
|
+
Live smoke tests against the real upstream API are skipped by default:
|
|
208
204
|
|
|
209
|
-
```
|
|
205
|
+
```bash
|
|
210
206
|
TUTTI_LIVE=1 npm test
|
|
211
207
|
```
|
|
212
208
|
|
|
213
|
-
Manual MCP checks:
|
|
209
|
+
Manual MCP checks with the inspector:
|
|
214
210
|
|
|
215
|
-
```
|
|
211
|
+
```bash
|
|
216
212
|
npx @modelcontextprotocol/inspector --cli --method tools/list node dist/mcp.js
|
|
217
213
|
npx @modelcontextprotocol/inspector --cli node dist/mcp.js --method tools/call --tool-name search_listings --tool-arg query=velo --tool-arg priceMax=300
|
|
218
214
|
```
|
|
219
215
|
|
|
220
216
|
Manual CLI check:
|
|
221
217
|
|
|
222
|
-
```
|
|
218
|
+
```bash
|
|
223
219
|
node dist/cli.js search velo --max 300 --limit 5
|
|
224
220
|
```
|
|
225
221
|
|
|
226
222
|
---
|
|
227
223
|
|
|
228
|
-
##
|
|
229
|
-
|
|
230
|
-
| Symptom | Fix |
|
|
231
|
-
| --- | --- |
|
|
232
|
-
| MCP client does not show the tools | Restart the client or start a new session so it respawns the server. |
|
|
233
|
-
| `location` matches the wrong place | Run `search_localities` first, then use a more specific place name. |
|
|
234
|
-
| Search fails with a rate-limit message | Wait a few minutes before retrying; the upstream API is behind Cloudflare. |
|
|
235
|
-
| CLI output is one line | Expected when stdout is not a TTY; pipe it through `jq` if needed. |
|
|
236
|
-
| Live tests are skipped | Set `TUTTI_LIVE=1` explicitly. |
|
|
237
|
-
| Inspector command opens a UI instead of running once | Add `--cli` and an explicit `--method`, as shown above. |
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
## Legal Caveat
|
|
224
|
+
## Legal caveat
|
|
242
225
|
|
|
243
|
-
This package uses a reverse-engineered private API via the `tutti-api` npm package. tutti.ch has no official public API, and its Nutzungsbedingungen prohibit automated queries and reproduction of listings. This project is intended for personal and prototype use only
|
|
226
|
+
This package uses a reverse-engineered private API via the [`tutti-api`](https://www.npmjs.com/package/tutti-api) npm package. tutti.ch has no official public API, and its Nutzungsbedingungen prohibit automated queries and reproduction of listings. This project is intended for personal and prototype use only — it deliberately provides no bulk-export or scraping features. Use it responsibly and respect tutti.ch's terms and rate limits.
|
|
244
227
|
|
|
245
228
|
## Disclaimer
|
|
246
229
|
|
|
@@ -248,4 +231,4 @@ This is an unofficial community project and is not affiliated with tutti.ch or S
|
|
|
248
231
|
|
|
249
232
|
## License
|
|
250
233
|
|
|
251
|
-
MIT
|
|
234
|
+
[MIT](./LICENSE)
|