@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 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
- # Temporary Holding Version
1
+ # 10ML Fragrance Index (MCP server, stdio)
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
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
+ [![npm](https://img.shields.io/npm/v/@10ml/perfume-finder-mcp?color=002AFF)](https://www.npmjs.com/package/@10ml/perfume-finder-mcp)
8
+ [![license](https://img.shields.io/npm/l/@10ml/perfume-finder-mcp?color=002AFF)](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": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
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
+ }