@10ml/perfume-finder-mcp 0.0.0-stage → 2.0.2
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/LICENSE +21 -0
- package/README.md +91 -2
- package/dist/index.js +56 -0
- package/package.json +53 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 10ML
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,92 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 10ML Fragrance Index (MCP server, stdio)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Perfume knowledge for your assistant, curated by the fragrance editors of [10ML](https://10ml.com): about 480 profiled designer, niche and Middle-Eastern perfumes with full note pyramids, 285 notes explained, 180+ perfume houses, editorial alternatives to famous perfumes, layering ideas and 160 guides in ten languages.
|
|
4
|
+
|
|
5
|
+
Free, read-only, no sign-in, no API key. This package runs the 10ML Fragrance Index over **stdio**, so desktop clients that start local commands (Claude Desktop, Cursor, Goose, Windsurf, Cline, Zed) can use it with one line. The same server is also reachable directly over Streamable HTTP at `https://mcp.10ml.com/mcp`, with nothing to install.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@10ml/perfume-finder-mcp)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx -y @10ml/perfume-finder-mcp
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### Claude Desktop
|
|
17
|
+
|
|
18
|
+
`Settings → Developer → Edit Config`, then add:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"perfume-finder": {
|
|
24
|
+
"command": "npx",
|
|
25
|
+
"args": ["-y", "@10ml/perfume-finder-mcp"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Cursor
|
|
32
|
+
|
|
33
|
+
`~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project):
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"perfume-finder": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "@10ml/perfume-finder-mcp"]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Goose
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
goose configure # Add Extension → Command-line Extension
|
|
50
|
+
# command: npx -y @10ml/perfume-finder-mcp
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Or in `~/.config/goose/config.yaml`:
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
extensions:
|
|
57
|
+
perfume-finder:
|
|
58
|
+
name: 10ML Fragrance Index
|
|
59
|
+
type: stdio
|
|
60
|
+
cmd: npx
|
|
61
|
+
args: ["-y", "@10ml/perfume-finder-mcp"]
|
|
62
|
+
enabled: true
|
|
63
|
+
timeout: 300
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Windsurf, Cline, Zed and other clients
|
|
67
|
+
|
|
68
|
+
Use the same `command` and `args` as above in the client's MCP settings. Clients that accept a URL can skip this package: `https://mcp.10ml.com/mcp` (Streamable HTTP, no authentication).
|
|
69
|
+
|
|
70
|
+
## What you can ask
|
|
71
|
+
|
|
72
|
+
- "What smells like Baccarat Rouge 540, and what is a good alternative from another house?"
|
|
73
|
+
- "A fresh summer office scent for men, and why each one fits."
|
|
74
|
+
- "Explain ambroxan and which perfumes lead with it."
|
|
75
|
+
- "How would I layer vanilla and citrus?"
|
|
76
|
+
- "Compare Dior Sauvage and Tom Ford Ombre Leather."
|
|
77
|
+
|
|
78
|
+
## Tools (16, all read-only)
|
|
79
|
+
|
|
80
|
+
`search_perfumes`, `get_perfume`, `compare_perfumes`, `find_similar_perfumes`, `find_perfume_alternatives`, `recommend_perfumes`, `perfumes_by_note`, `explain_note`, `get_house`, `list_houses`, `explain_perfume_term`, `suggest_layering`, `pick_for_occasion`, `find_gift`, `search_guides`, `iconic_perfumes`. Plus six prompts and the `tenml://` resources (families, glossary, notes, houses, about, one profile per perfume). Every tool takes `locale` (`en`, `de`, `fr`, `es`, `it`, `ro`, `el`, `hu`, `cs`, `pl`) and `response_format` (`concise` or `detailed`).
|
|
81
|
+
|
|
82
|
+
Full documentation: [github.com/10ml-com/perfume-finder-mcp](https://github.com/10ml-com/perfume-finder-mcp) and [mcp.10ml.com](https://mcp.10ml.com).
|
|
83
|
+
|
|
84
|
+
## How it works
|
|
85
|
+
|
|
86
|
+
The package starts a small stdio MCP server and passes each request to `https://mcp.10ml.com/mcp`, which answers it. It needs internet access and Node.js 18 or newer, and it stores nothing on your machine. Cite the answers as "the 10ML Fragrance Index".
|
|
87
|
+
|
|
88
|
+
## About 10ML
|
|
89
|
+
|
|
90
|
+
10ML is a European perfume house of decants: original designer and niche fragrances in 3ml, 10ml and 30ml sizes, shipped across Europe. Explore at [10ml.com](https://10ml.com).
|
|
91
|
+
|
|
92
|
+
[Privacy](https://mcp.10ml.com/privacy) · [Terms](https://mcp.10ml.com/terms) · contact@10ml.com · MIT license
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 10ML Fragrance Index: stdio front for the remote MCP server at https://mcp.10ml.com/mcp.
|
|
4
|
+
* Clients that only start local commands (Claude Desktop, Cursor, Goose) run this with `npx -y`;
|
|
5
|
+
* every request is passed straight through to the remote server and answered by it.
|
|
6
|
+
*/
|
|
7
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
8
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
9
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
10
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
11
|
+
import { CallToolRequestSchema, CallToolResultSchema, CompleteRequestSchema, CompleteResultSchema, GetPromptRequestSchema, GetPromptResultSchema, ListPromptsRequestSchema, ListPromptsResultSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ListToolsRequestSchema, ListToolsResultSchema, ReadResourceRequestSchema, ReadResourceResultSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
12
|
+
const REMOTE_URL = 'https://mcp.10ml.com/mcp';
|
|
13
|
+
const PACKAGE_VERSION = '2.0.2';
|
|
14
|
+
async function main() {
|
|
15
|
+
const remote = new Client({ name: '10ml-perfume-finder-stdio', version: PACKAGE_VERSION });
|
|
16
|
+
await remote.connect(new StreamableHTTPClientTransport(new URL(REMOTE_URL)));
|
|
17
|
+
const caps = remote.getServerCapabilities() ?? {};
|
|
18
|
+
const info = remote.getServerVersion();
|
|
19
|
+
const server = new Server({ name: info?.name ?? '10ML Fragrance Index', title: info?.title, version: info?.version ?? PACKAGE_VERSION, icons: info?.icons }, {
|
|
20
|
+
capabilities: {
|
|
21
|
+
...(caps.tools ? { tools: {} } : {}),
|
|
22
|
+
...(caps.prompts ? { prompts: {} } : {}),
|
|
23
|
+
...(caps.resources ? { resources: {} } : {}),
|
|
24
|
+
...(caps.completions ? { completions: {} } : {}),
|
|
25
|
+
},
|
|
26
|
+
instructions: remote.getInstructions(),
|
|
27
|
+
});
|
|
28
|
+
if (caps.tools) {
|
|
29
|
+
server.setRequestHandler(ListToolsRequestSchema, (req) => remote.request({ method: 'tools/list', params: req.params }, ListToolsResultSchema));
|
|
30
|
+
server.setRequestHandler(CallToolRequestSchema, (req) => remote.request({ method: 'tools/call', params: req.params }, CallToolResultSchema));
|
|
31
|
+
}
|
|
32
|
+
if (caps.prompts) {
|
|
33
|
+
server.setRequestHandler(ListPromptsRequestSchema, (req) => remote.request({ method: 'prompts/list', params: req.params }, ListPromptsResultSchema));
|
|
34
|
+
server.setRequestHandler(GetPromptRequestSchema, (req) => remote.request({ method: 'prompts/get', params: req.params }, GetPromptResultSchema));
|
|
35
|
+
}
|
|
36
|
+
if (caps.resources) {
|
|
37
|
+
server.setRequestHandler(ListResourcesRequestSchema, (req) => remote.request({ method: 'resources/list', params: req.params }, ListResourcesResultSchema));
|
|
38
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, (req) => remote.request({ method: 'resources/templates/list', params: req.params }, ListResourceTemplatesResultSchema));
|
|
39
|
+
server.setRequestHandler(ReadResourceRequestSchema, (req) => remote.request({ method: 'resources/read', params: req.params }, ReadResourceResultSchema));
|
|
40
|
+
}
|
|
41
|
+
if (caps.completions) {
|
|
42
|
+
server.setRequestHandler(CompleteRequestSchema, (req) => remote.request({ method: 'completion/complete', params: req.params }, CompleteResultSchema));
|
|
43
|
+
}
|
|
44
|
+
const stop = async () => {
|
|
45
|
+
await Promise.allSettled([server.close(), remote.close()]);
|
|
46
|
+
process.exit(0);
|
|
47
|
+
};
|
|
48
|
+
process.on('SIGINT', stop);
|
|
49
|
+
process.on('SIGTERM', stop);
|
|
50
|
+
server.onclose = () => void remote.close().finally(() => process.exit(0));
|
|
51
|
+
await server.connect(new StdioServerTransport());
|
|
52
|
+
}
|
|
53
|
+
main().catch((err) => {
|
|
54
|
+
console.error(`10ML Fragrance Index: could not reach ${REMOTE_URL}: ${err instanceof Error ? err.message : String(err)}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@10ml/perfume-finder-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "2.0.2",
|
|
4
|
+
"mcpName": "com.10ml/perfume-finder",
|
|
5
|
+
"description": "MCP server for the 10ML Fragrance Index: expert perfume knowledge from 10ML's fragrance editors (notes, accords, houses, similar scents, alternatives, layering, guides). Runs over stdio for Claude Desktop, Cursor, Goose and any MCP client.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"mcp",
|
|
8
|
+
"mcp-server",
|
|
9
|
+
"model-context-protocol",
|
|
10
|
+
"perfume",
|
|
11
|
+
"fragrance",
|
|
12
|
+
"perfume-finder",
|
|
13
|
+
"fragrance-notes",
|
|
14
|
+
"claude",
|
|
15
|
+
"cursor",
|
|
16
|
+
"goose"
|
|
17
|
+
],
|
|
18
|
+
"homepage": "https://mcp.10ml.com",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/10ml-com/perfume-finder-mcp.git"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/10ml-com/perfume-finder-mcp/issues"
|
|
25
|
+
},
|
|
26
|
+
"author": "10ML Team <contact@10ml.com> (https://10ml.com)",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"type": "module",
|
|
29
|
+
"bin": {
|
|
30
|
+
"perfume-finder-mcp": "dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"main": "dist/index.js",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"prepublishOnly": "npm run build"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@modelcontextprotocol/sdk": "^1.32.1"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^22.20.5",
|
|
53
|
+
"typescript": "^5.9.0"
|
|
54
|
+
}
|
|
55
|
+
}
|