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.
Files changed (2) hide show
  1. package/README.md +74 -91
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,54 +1,37 @@
1
- # tutti-mcp
1
+ # 🇨🇭 tutti MCP
2
2
 
3
- > Search tutti.ch Swiss classifieds from an AI agent or a JSON CLI — anonymous and read-only.
3
+ > Search tutti.ch Swiss classifieds from your AI agent or the command line**anonymous and read-only by design**.
4
4
 
5
+ [![npm version](https://img.shields.io/npm/v/tutti-mcp.svg)](https://www.npmjs.com/package/tutti-mcp)
6
+ [![npm downloads](https://img.shields.io/npm/dm/tutti-mcp.svg)](https://www.npmjs.com/package/tutti-mcp)
7
+ [![license](https://img.shields.io/npm/l/tutti-mcp.svg)](./LICENSE)
5
8
  [![MCP](https://img.shields.io/badge/MCP-server-blue)](https://modelcontextprotocol.io)
6
- [![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
7
9
 
8
- `tutti-mcp` exposes the same compact tutti.ch search core through two entry points:
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 near Bern."
17
- - "Get details for tutti listing 81828298."
18
- - "Show me the available tutti categories."
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
- The package is intentionally anonymous read-only: no login, messaging, favorites, posting, caching, or bulk export.
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 Start
25
-
26
- After publishing to npm, run the MCP server directly with `npx`:
23
+ ## Quick start
27
24
 
28
- ```sh
25
+ ```bash
29
26
  npx -y tutti-mcp
30
27
  ```
31
28
 
32
- Use the CLI through the `tutti` bin:
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
- ```sh
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
- ```sh
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; MCP tools are injected when the session starts.
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
- Requires Node.js 20 or newer.
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, for example `"40.-"`.
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. Pass that value back as `cursor`.
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 Workflows
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. Use `get_listing` for the items that need full details.
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
- **Use from the CLI**
121
+ ---
141
122
 
142
- ```sh
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
- Installed package bins:
125
+ The package also installs a `tutti` bin with subcommands mirroring the MCP tools:
151
126
 
152
- ```sh
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
- tutti search velo --max 300 --limit 5
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
- All CLI commands print JSON to stdout. Output is pretty-printed on a TTY and compact otherwise. Errors are written to stderr and return exit code 1.
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 Model
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 `tutti-api` objects are returned to agents. Responses are mapped to compact project-owned payloads.
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
- ## Develop From Source
167
+ ## Troubleshooting
179
168
 
180
- ```sh
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
- ```sh
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
- ```sh
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
- ```sh
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
- ```sh
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
- ```sh
218
+ ```bash
223
219
  node dist/cli.js search velo --max 300 --limit 5
224
220
  ```
225
221
 
226
222
  ---
227
223
 
228
- ## Troubleshooting
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. It does not provide bulk-export or scraping features. Use it responsibly and respect tutti.ch's terms and rate limits.
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tutti-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "MCP server and CLI for searching tutti.ch classifieds.",
5
5
  "license": "MIT",
6
6
  "author": "domwoe",