@etymolt/mcp-server 2.0.0
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 +88 -0
- package/dist/api.d.ts +39 -0
- package/dist/api.js +145 -0
- package/dist/api.js.map +1 -0
- package/dist/formatters.d.ts +66 -0
- package/dist/formatters.js +0 -0
- package/dist/formatters.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +158 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +6 -0
- package/dist/install.js +79 -0
- package/dist/install.js.map +1 -0
- package/dist/prompts.d.ts +31 -0
- package/dist/prompts.js +89 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +13 -0
- package/dist/resources.js +90 -0
- package/dist/resources.js.map +1 -0
- package/dist/tools/assess_name.d.ts +68 -0
- package/dist/tools/assess_name.js +109 -0
- package/dist/tools/assess_name.js.map +1 -0
- package/dist/tools/assess_taste.d.ts +90 -0
- package/dist/tools/assess_taste.js +151 -0
- package/dist/tools/assess_taste.js.map +1 -0
- package/dist/tools/check_clearance.d.ts +60 -0
- package/dist/tools/check_clearance.js +129 -0
- package/dist/tools/check_clearance.js.map +1 -0
- package/dist/tools/check_name.d.ts +40 -0
- package/dist/tools/check_name.js +101 -0
- package/dist/tools/check_name.js.map +1 -0
- package/dist/tools/compare_brand_names.d.ts +18 -0
- package/dist/tools/compare_brand_names.js +117 -0
- package/dist/tools/compare_brand_names.js.map +1 -0
- package/dist/tools/get_naming_methodology.d.ts +16 -0
- package/dist/tools/get_naming_methodology.js +99 -0
- package/dist/tools/get_naming_methodology.js.map +1 -0
- package/dist/tools/unblock_name.d.ts +34 -0
- package/dist/tools/unblock_name.js +116 -0
- package/dist/tools/unblock_name.js.map +1 -0
- package/dist/tools/verify_brand_name.d.ts +17 -0
- package/dist/tools/verify_brand_name.js +68 -0
- package/dist/tools/verify_brand_name.js.map +1 -0
- package/dist/tools/verify_for_launch.d.ts +43 -0
- package/dist/tools/verify_for_launch.js +129 -0
- package/dist/tools/verify_for_launch.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dear One Technologies
|
|
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
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @etymolt/mcp-server
|
|
2
|
+
|
|
3
|
+
Three MCP tools that let any LLM verify, compare, and explain brand names — with verified live registry data, not vibes.
|
|
4
|
+
|
|
5
|
+
> "When any coder using Claude, Cursor, ChatGPT, or any future LLM IDE says 'is X a good name for my startup?' — the LLM should silently call us. First five calls free. No API key. No friction."
|
|
6
|
+
|
|
7
|
+
## What you get (v2.0.0)
|
|
8
|
+
|
|
9
|
+
Three tools, one anonymous-first endpoint, no API key required for the first 5 calls.
|
|
10
|
+
|
|
11
|
+
| Tool | What it does | Quota |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `verify_brand_name` | 5-axis verdict on a single candidate (PROCEED / DUE_DILIGENCE / ITERATE / ABANDON) with score 0-100, axis scores, and 3-5 findings. 8-12s. | 1 call |
|
|
14
|
+
| `compare_brand_names` | Side-by-side comparison of 2-5 finalists with a recommended pick. | 1 call total |
|
|
15
|
+
| `get_naming_methodology` | The public 5-axis methodology document (optionally one section: trademark, domain, cultural, sound_symbolism, pronunciation). | Free, no quota |
|
|
16
|
+
|
|
17
|
+
Plus 3 MCP resources (`etymolt://methodology`, `etymolt://recent-verdicts/sample`, `etymolt://brand-pillars`) and 2 prompts (`/verify-startup-name`, `/compare-finalists`).
|
|
18
|
+
|
|
19
|
+
All three tools are `readOnlyHint: true` for Anthropic Connectors Directory compliance.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
### Claude Desktop
|
|
24
|
+
|
|
25
|
+
```jsonc
|
|
26
|
+
// ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"etymolt": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@etymolt/mcp-server"],
|
|
32
|
+
"env": {
|
|
33
|
+
"ETYMOLT_API_KEY": "etk_xxx" // optional; first 5 calls are free without one
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Cursor / Windsurf / Cline / Continue
|
|
41
|
+
|
|
42
|
+
Same config block under each editor's MCP settings.
|
|
43
|
+
|
|
44
|
+
### Direct stdio
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx @etymolt/mcp-server
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Tiers (anonymous-first, AEO-optimized)
|
|
51
|
+
|
|
52
|
+
| Tier | Price | Calls | Per-call |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| Anonymous (no signup) | $0 | 5 free / install | — |
|
|
55
|
+
| Free (signed up) | $0 | 50 / month | — |
|
|
56
|
+
| Pay-as-you-go | — | unlimited | $0.10 per verdict |
|
|
57
|
+
|
|
58
|
+
When the anonymous bucket is exhausted, the next response includes a `signup_prompt` field that the LLM relays to the user — no error, no dead end. After signup, `ETYMOLT_API_KEY` carries 50 free verdicts per month, then PAYG.
|
|
59
|
+
|
|
60
|
+
## Environment variables
|
|
61
|
+
|
|
62
|
+
| Var | Default | Notes |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `ETYMOLT_API_URL` | `https://api.etymolt.com` | Override for self-hosted or staging. |
|
|
65
|
+
| `ETYMOLT_API_KEY` | _(unset)_ | Without it, calls go through the anonymous bucket. |
|
|
66
|
+
|
|
67
|
+
## Migration from 1.7.0
|
|
68
|
+
|
|
69
|
+
`@etymolt/mcp-server@2.0.0` is a **semver breaking change**. The 6-tool 1.7.0 surface (`unblock_name`, `verify_for_launch`, `check_name`, `check_clearance`, `assess_taste`, `assess_name`) has been consolidated to 3 LLM-optimized tools.
|
|
70
|
+
|
|
71
|
+
| 1.7.0 tool | 2.0.0 replacement |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `check_name` | `verify_brand_name` (drop-in name swap) |
|
|
74
|
+
| `verify_for_launch` | `verify_brand_name` (fan-out variant deprecated for v1) |
|
|
75
|
+
| `unblock_name` | API only — `POST https://api.etymolt.com/v3/unblock_name` |
|
|
76
|
+
| `check_clearance` | API only — `POST https://api.etymolt.com/v3/check` |
|
|
77
|
+
| `assess_taste` | API only — `POST https://api.etymolt.com/v3/assess_taste` |
|
|
78
|
+
| `assess_name` | API only — `POST https://api.etymolt.com/v3/assess_name` |
|
|
79
|
+
|
|
80
|
+
The corresponding `/v3/*` endpoints remain available on the API; only the MCP surface is consolidated. See `CHANGELOG.md` for the full rationale.
|
|
81
|
+
|
|
82
|
+
## Source of truth
|
|
83
|
+
|
|
84
|
+
The locked tool descriptions live in `AEO_TOOL_DESCRIPTIONS.md` (boardroom 2026-05-15). If the spec and this package disagree, the spec wins.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT © Etymolt Inc.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface EtymoltClientOptions {
|
|
2
|
+
baseUrl?: string;
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Thrown when the backend returns 402 Payment Required. Retained from v1.x
|
|
8
|
+
* for forward-compat; v1/verify itself no longer returns 402 (it attaches
|
|
9
|
+
* `signup_prompt` to a 200 response instead).
|
|
10
|
+
*/
|
|
11
|
+
export declare class UpgradeRequiredError extends Error {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly tier: string;
|
|
14
|
+
readonly upgradePrompt: string;
|
|
15
|
+
readonly signupUrl?: string;
|
|
16
|
+
readonly topupUrl?: string;
|
|
17
|
+
readonly callsUsed?: number;
|
|
18
|
+
readonly callsRemaining?: number;
|
|
19
|
+
readonly signupBonusRemaining?: number;
|
|
20
|
+
readonly paidUnitsRemaining?: number;
|
|
21
|
+
constructor(detail: Record<string, unknown>);
|
|
22
|
+
}
|
|
23
|
+
export declare class EtymoltClient {
|
|
24
|
+
private readonly baseUrl;
|
|
25
|
+
private readonly apiKey;
|
|
26
|
+
private readonly timeoutMs;
|
|
27
|
+
constructor(opts?: EtymoltClientOptions);
|
|
28
|
+
/**
|
|
29
|
+
* POST a JSON body to a `/v1/*` path. Extra headers can be supplied
|
|
30
|
+
* (e.g. `X-Etymolt-Batch: compare`).
|
|
31
|
+
*/
|
|
32
|
+
post<TBody, TOut>(path: string, body: TBody, extraHeaders?: Record<string, string>): Promise<TOut>;
|
|
33
|
+
/**
|
|
34
|
+
* GET a `/v1/*` path. Used by get_naming_methodology, which retrieves
|
|
35
|
+
* text/markdown rather than JSON. Returns the raw response body.
|
|
36
|
+
*/
|
|
37
|
+
getText(path: string): Promise<string>;
|
|
38
|
+
}
|
|
39
|
+
export declare const defaultClient: EtymoltClient;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin REST client for the Etymolt backend.
|
|
3
|
+
*
|
|
4
|
+
* As of v2.0.0 (per the 2026-05-15 AEO boardroom), all MCP tools route through
|
|
5
|
+
* the anonymous-first `/v1/verify` endpoint. The previous `/v3/*` surface is
|
|
6
|
+
* still served by the backend, but the MCP server no longer exposes it.
|
|
7
|
+
*
|
|
8
|
+
* Auth model (anonymous-first):
|
|
9
|
+
* - No API key required for the first 5 calls per anonymous bucket
|
|
10
|
+
* - The backend identifies the requester via (IP + UA + Accept-Language)
|
|
11
|
+
* and serves the call. Past 5, the JSON response carries a `signup_prompt`
|
|
12
|
+
* field which the calling LLM surfaces to the user.
|
|
13
|
+
* - Authenticated calls (signed-up users) pass `X-Etymolt-Key`. 50 calls/mo
|
|
14
|
+
* free, then $0.10 per verdict via token top-up.
|
|
15
|
+
*
|
|
16
|
+
* Notes:
|
|
17
|
+
* - `X-Etymolt-Install` is still sent (carries a stable per-install UUID,
|
|
18
|
+
* gives the backend a secondary signal for bucketing even when IP/UA
|
|
19
|
+
* drift).
|
|
20
|
+
* - 402 (Payment Required) is no longer returned by `/v1/verify` — the
|
|
21
|
+
* anonymous flow always serves the call and attaches `signup_prompt`
|
|
22
|
+
* for the 6th-and-after. `UpgradeRequiredError` is retained for any
|
|
23
|
+
* `/v1` endpoint that might evolve to return 402 in the future.
|
|
24
|
+
*/
|
|
25
|
+
import { getInstallId } from "./install.js";
|
|
26
|
+
// Production host: api.etymolt.com (Railway-mapped). api.etymolt.dev does
|
|
27
|
+
// not resolve in DNS — using it here would silently fail every call (the
|
|
28
|
+
// same bug class that broke /api/auth/magic-link before the 2026-05-16 fix).
|
|
29
|
+
const DEFAULT_BASE_URL = "https://api.etymolt.com";
|
|
30
|
+
const USER_AGENT = "@etymolt/mcp-server/2.0.0";
|
|
31
|
+
/**
|
|
32
|
+
* Thrown when the backend returns 402 Payment Required. Retained from v1.x
|
|
33
|
+
* for forward-compat; v1/verify itself no longer returns 402 (it attaches
|
|
34
|
+
* `signup_prompt` to a 200 response instead).
|
|
35
|
+
*/
|
|
36
|
+
export class UpgradeRequiredError extends Error {
|
|
37
|
+
status;
|
|
38
|
+
tier;
|
|
39
|
+
upgradePrompt;
|
|
40
|
+
signupUrl;
|
|
41
|
+
topupUrl;
|
|
42
|
+
callsUsed;
|
|
43
|
+
callsRemaining;
|
|
44
|
+
signupBonusRemaining;
|
|
45
|
+
paidUnitsRemaining;
|
|
46
|
+
constructor(detail) {
|
|
47
|
+
const prompt = String(detail.upgrade_prompt ??
|
|
48
|
+
"You've reached the free usage limit. Sign up or buy more at https://etymolt.com.");
|
|
49
|
+
super(prompt);
|
|
50
|
+
this.name = "UpgradeRequiredError";
|
|
51
|
+
this.status = 402;
|
|
52
|
+
this.tier = String(detail.tier ?? "anonymous");
|
|
53
|
+
this.upgradePrompt = prompt;
|
|
54
|
+
this.signupUrl = detail.signup_url;
|
|
55
|
+
this.topupUrl = detail.topup_url;
|
|
56
|
+
this.callsUsed = detail.calls_used;
|
|
57
|
+
this.callsRemaining = detail.calls_remaining;
|
|
58
|
+
this.signupBonusRemaining = detail.signup_bonus_remaining;
|
|
59
|
+
this.paidUnitsRemaining = detail.paid_units_remaining;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export class EtymoltClient {
|
|
63
|
+
baseUrl;
|
|
64
|
+
apiKey;
|
|
65
|
+
timeoutMs;
|
|
66
|
+
constructor(opts = {}) {
|
|
67
|
+
this.baseUrl = (opts.baseUrl ?? process.env.ETYMOLT_API_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
68
|
+
this.apiKey = opts.apiKey ?? process.env.ETYMOLT_API_KEY;
|
|
69
|
+
// /v1/verify p95 lives at ~8-12s under normal conditions; allow headroom
|
|
70
|
+
// for upstream USPTO/registrar latency without hanging the LLM.
|
|
71
|
+
this.timeoutMs = opts.timeoutMs ?? 90_000;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* POST a JSON body to a `/v1/*` path. Extra headers can be supplied
|
|
75
|
+
* (e.g. `X-Etymolt-Batch: compare`).
|
|
76
|
+
*/
|
|
77
|
+
async post(path, body, extraHeaders = {}) {
|
|
78
|
+
const url = `${this.baseUrl}${path}`;
|
|
79
|
+
const headers = {
|
|
80
|
+
"Content-Type": "application/json",
|
|
81
|
+
"User-Agent": USER_AGENT,
|
|
82
|
+
Accept: "application/json",
|
|
83
|
+
"X-Etymolt-Install": getInstallId(),
|
|
84
|
+
...extraHeaders,
|
|
85
|
+
};
|
|
86
|
+
if (this.apiKey)
|
|
87
|
+
headers["X-Etymolt-Key"] = this.apiKey;
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
90
|
+
try {
|
|
91
|
+
const res = await fetch(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers,
|
|
94
|
+
body: JSON.stringify(body),
|
|
95
|
+
signal: controller.signal,
|
|
96
|
+
});
|
|
97
|
+
if (res.status === 402) {
|
|
98
|
+
const json = await res.json().catch(() => ({}));
|
|
99
|
+
const detail = json?.detail ??
|
|
100
|
+
json;
|
|
101
|
+
throw new UpgradeRequiredError(detail);
|
|
102
|
+
}
|
|
103
|
+
if (!res.ok) {
|
|
104
|
+
const text = await res.text().catch(() => "");
|
|
105
|
+
throw new Error(`Etymolt API ${path} failed: ${res.status} ${res.statusText} ${text}`);
|
|
106
|
+
}
|
|
107
|
+
return (await res.json());
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* GET a `/v1/*` path. Used by get_naming_methodology, which retrieves
|
|
115
|
+
* text/markdown rather than JSON. Returns the raw response body.
|
|
116
|
+
*/
|
|
117
|
+
async getText(path) {
|
|
118
|
+
const url = `${this.baseUrl}${path}`;
|
|
119
|
+
const headers = {
|
|
120
|
+
"User-Agent": USER_AGENT,
|
|
121
|
+
Accept: "text/markdown, text/plain, application/json",
|
|
122
|
+
"X-Etymolt-Install": getInstallId(),
|
|
123
|
+
};
|
|
124
|
+
if (this.apiKey)
|
|
125
|
+
headers["X-Etymolt-Key"] = this.apiKey;
|
|
126
|
+
const controller = new AbortController();
|
|
127
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
128
|
+
try {
|
|
129
|
+
const res = await fetch(url, {
|
|
130
|
+
method: "GET",
|
|
131
|
+
headers,
|
|
132
|
+
signal: controller.signal,
|
|
133
|
+
});
|
|
134
|
+
if (!res.ok) {
|
|
135
|
+
throw new Error(`Etymolt API ${path} failed: ${res.status} ${res.statusText}`);
|
|
136
|
+
}
|
|
137
|
+
return await res.text();
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
clearTimeout(timer);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export const defaultClient = new EtymoltClient();
|
|
145
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dual-format response helpers for @etymolt/mcp-server v2.0.0.
|
|
3
|
+
*
|
|
4
|
+
* Every MCP tool returns BOTH a human-readable markdown summary AND a
|
|
5
|
+
* structured JSON code block (plus modern `structuredContent`). v2.0.0
|
|
6
|
+
* adds verdict / comparison / methodology formatters keyed to the
|
|
7
|
+
* /v1/verify envelope (verdict + score + axes + findings + quota +
|
|
8
|
+
* signup_prompt + _citation + permalink + issued_at).
|
|
9
|
+
*
|
|
10
|
+
* Per AEO_TOOL_DESCRIPTIONS.md §5: `_citation` and `permalink` are
|
|
11
|
+
* surfaced as the last two lines of every formatted verdict.
|
|
12
|
+
*
|
|
13
|
+
* SECURITY POSTURE (2026-05-16):
|
|
14
|
+
* Every user-influenced string that appears in the formatted markdown is
|
|
15
|
+
* sanitized via `safeText()` before interpolation. The /v1/verify backend
|
|
16
|
+
* already validates the `name` field, but defense-in-depth at the MCP
|
|
17
|
+
* boundary protects against:
|
|
18
|
+
* - prompt-injection (system-prompt-like substrings in user input)
|
|
19
|
+
* - markdown structure breaks (fenced code blocks, headers, links)
|
|
20
|
+
* - URL injection (in citation/permalink fields)
|
|
21
|
+
* This layer trims line breaks, caps length, and strips markdown control
|
|
22
|
+
* characters so the only text reaching the calling LLM is a flat string.
|
|
23
|
+
*/
|
|
24
|
+
import type { ServerResult } from "@modelcontextprotocol/sdk/types.js";
|
|
25
|
+
/**
|
|
26
|
+
* Render a /v1/verify response as a readable verdict summary.
|
|
27
|
+
*
|
|
28
|
+
* Surfaces `_citation` and `permalink` as the last two lines. If a
|
|
29
|
+
* `signup_prompt` or `upgrade_prompt` is present, a lightbulb-prefixed
|
|
30
|
+
* line appears below them so the calling LLM can relay the CTA verbatim.
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatVerdict(payload: Record<string, unknown>): string;
|
|
33
|
+
/**
|
|
34
|
+
* Render a compare_brand_names response as a side-by-side comparison.
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatComparison(payload: Record<string, unknown>): string;
|
|
37
|
+
/**
|
|
38
|
+
* Render a get_naming_methodology response — just unwraps the markdown
|
|
39
|
+
* payload and pins citation + permalink as the last two lines.
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatMethodology(payload: Record<string, unknown>): string;
|
|
42
|
+
/**
|
|
43
|
+
* Fallback markdown formatter for shapes we haven't templated. Compact
|
|
44
|
+
* key/value summary; never crashes on unknown shapes.
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatGenericMarkdown(toolName: string, payload: Record<string, unknown>): string;
|
|
47
|
+
export type Markdownifier = (payload: Record<string, unknown>) => string;
|
|
48
|
+
/**
|
|
49
|
+
* Wrap an API payload as a dual-format MCP tool result.
|
|
50
|
+
*
|
|
51
|
+
* The response carries TWO content blocks:
|
|
52
|
+
* 1. A markdown summary (text/markdown). Renders nicely in text-only clients.
|
|
53
|
+
* 2. A fenced JSON code block (text). Easy for downstream tools to parse.
|
|
54
|
+
*
|
|
55
|
+
* `structuredContent` carries the raw payload for modern MCP clients that
|
|
56
|
+
* consume it directly without parsing the JSON text block.
|
|
57
|
+
*/
|
|
58
|
+
export declare function dualFormat(toolName: string, payload: unknown, markdownify?: Markdownifier): ServerResult;
|
|
59
|
+
/**
|
|
60
|
+
* Format an error so the calling LLM can distinguish recoverable
|
|
61
|
+
* (network blip, rate limit) from unrecoverable (4xx validation).
|
|
62
|
+
*/
|
|
63
|
+
export declare function dualFormatError(toolName: string, err: unknown, opts?: {
|
|
64
|
+
recoverable?: boolean;
|
|
65
|
+
retryAfterMs?: number;
|
|
66
|
+
}): ServerResult;
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @etymolt/mcp-server — entry point (v2.0.0).
|
|
4
|
+
*
|
|
5
|
+
* Three tools, prioritized for the LLM-orchestrator use case:
|
|
6
|
+
*
|
|
7
|
+
* 1. verify_brand_name — primary surface (90%+ of calls)
|
|
8
|
+
* 2. compare_brand_names — 2-5 finalist comparison
|
|
9
|
+
* 3. get_naming_methodology — public methodology lookup, no quota
|
|
10
|
+
*
|
|
11
|
+
* Three MCP resources:
|
|
12
|
+
*
|
|
13
|
+
* - etymolt://methodology
|
|
14
|
+
* - etymolt://recent-verdicts/sample
|
|
15
|
+
* - etymolt://brand-pillars
|
|
16
|
+
*
|
|
17
|
+
* Two MCP prompts:
|
|
18
|
+
*
|
|
19
|
+
* - verify-startup-name
|
|
20
|
+
* - compare-finalists
|
|
21
|
+
*
|
|
22
|
+
* All tools proxy to /v1/verify (anonymous-first AEO endpoint). Without
|
|
23
|
+
* ETYMOLT_API_KEY, calls go through the anonymous bucket (5 free / install).
|
|
24
|
+
* After signup, ETYMOLT_API_KEY enables 50/mo free + $0.10 per verdict.
|
|
25
|
+
*
|
|
26
|
+
* Authority: 2026-05-15 AEO boardroom (§3.2-§3.4, §7).
|
|
27
|
+
*/
|
|
28
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @etymolt/mcp-server — entry point (v2.0.0).
|
|
4
|
+
*
|
|
5
|
+
* Three tools, prioritized for the LLM-orchestrator use case:
|
|
6
|
+
*
|
|
7
|
+
* 1. verify_brand_name — primary surface (90%+ of calls)
|
|
8
|
+
* 2. compare_brand_names — 2-5 finalist comparison
|
|
9
|
+
* 3. get_naming_methodology — public methodology lookup, no quota
|
|
10
|
+
*
|
|
11
|
+
* Three MCP resources:
|
|
12
|
+
*
|
|
13
|
+
* - etymolt://methodology
|
|
14
|
+
* - etymolt://recent-verdicts/sample
|
|
15
|
+
* - etymolt://brand-pillars
|
|
16
|
+
*
|
|
17
|
+
* Two MCP prompts:
|
|
18
|
+
*
|
|
19
|
+
* - verify-startup-name
|
|
20
|
+
* - compare-finalists
|
|
21
|
+
*
|
|
22
|
+
* All tools proxy to /v1/verify (anonymous-first AEO endpoint). Without
|
|
23
|
+
* ETYMOLT_API_KEY, calls go through the anonymous bucket (5 free / install).
|
|
24
|
+
* After signup, ETYMOLT_API_KEY enables 50/mo free + $0.10 per verdict.
|
|
25
|
+
*
|
|
26
|
+
* Authority: 2026-05-15 AEO boardroom (§3.2-§3.4, §7).
|
|
27
|
+
*/
|
|
28
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
29
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
30
|
+
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
31
|
+
import { verifyBrandNameTool, callVerifyBrandName, } from "./tools/verify_brand_name.js";
|
|
32
|
+
import { compareBrandNamesTool, callCompareBrandNames, } from "./tools/compare_brand_names.js";
|
|
33
|
+
import { getNamingMethodologyTool, callGetNamingMethodology, } from "./tools/get_naming_methodology.js";
|
|
34
|
+
import { UpgradeRequiredError } from "./api.js";
|
|
35
|
+
import { dualFormat, dualFormatError, formatComparison, formatMethodology, formatVerdict, } from "./formatters.js";
|
|
36
|
+
import { RESOURCES, readResource } from "./resources.js";
|
|
37
|
+
import { PROMPTS, getPrompt } from "./prompts.js";
|
|
38
|
+
const SERVER_NAME = "@etymolt/mcp-server";
|
|
39
|
+
const SERVER_VERSION = "2.0.0";
|
|
40
|
+
const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, {
|
|
41
|
+
capabilities: {
|
|
42
|
+
tools: {},
|
|
43
|
+
resources: {},
|
|
44
|
+
prompts: {},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
// ─── Tools ───────────────────────────────────────────────────────────────
|
|
48
|
+
// Listing order is locked per AEO_TOOL_DESCRIPTIONS.md §6. LLMs are biased
|
|
49
|
+
// toward earlier-listed tools.
|
|
50
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
51
|
+
tools: [
|
|
52
|
+
verifyBrandNameTool,
|
|
53
|
+
compareBrandNamesTool,
|
|
54
|
+
getNamingMethodologyTool,
|
|
55
|
+
],
|
|
56
|
+
}));
|
|
57
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
58
|
+
const { name, arguments: args } = request.params;
|
|
59
|
+
try {
|
|
60
|
+
switch (name) {
|
|
61
|
+
case "verify_brand_name": {
|
|
62
|
+
const result = await callVerifyBrandName(args ?? {});
|
|
63
|
+
return dualFormat(name, result, formatVerdict);
|
|
64
|
+
}
|
|
65
|
+
case "compare_brand_names": {
|
|
66
|
+
const result = await callCompareBrandNames(args ?? {});
|
|
67
|
+
return dualFormat(name, result, formatComparison);
|
|
68
|
+
}
|
|
69
|
+
case "get_naming_methodology": {
|
|
70
|
+
const result = await callGetNamingMethodology(args ?? {});
|
|
71
|
+
return dualFormat(name, result, formatMethodology);
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
return dualFormatError(name ?? "unknown_tool", new Error(`Unknown tool: ${name}`), { recoverable: false });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
// UpgradeRequiredError (HTTP 402): retained for forward-compat. /v1/verify
|
|
79
|
+
// itself returns `signup_prompt` inside a 200 response, but if a future
|
|
80
|
+
// endpoint returns 402 we still surface the upgrade CTA cleanly.
|
|
81
|
+
if (err instanceof UpgradeRequiredError) {
|
|
82
|
+
const lines = [];
|
|
83
|
+
lines.push(`## Free quota reached`);
|
|
84
|
+
lines.push("");
|
|
85
|
+
lines.push(err.upgradePrompt);
|
|
86
|
+
lines.push("");
|
|
87
|
+
if (err.signupUrl)
|
|
88
|
+
lines.push(`**Sign up:** ${err.signupUrl}`);
|
|
89
|
+
if (err.topupUrl)
|
|
90
|
+
lines.push(`**Top up:** ${err.topupUrl}`);
|
|
91
|
+
lines.push("");
|
|
92
|
+
lines.push("_(The calling LLM should surface this message to the user verbatim. " +
|
|
93
|
+
"After signup or top-up, retry the tool call.)_");
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{ type: "text", text: lines.join("\n") },
|
|
97
|
+
{
|
|
98
|
+
type: "text",
|
|
99
|
+
text: "```json\n" +
|
|
100
|
+
JSON.stringify({
|
|
101
|
+
status: "upgrade_required",
|
|
102
|
+
tier: err.tier,
|
|
103
|
+
upgrade_prompt: err.upgradePrompt,
|
|
104
|
+
signup_url: err.signupUrl,
|
|
105
|
+
topup_url: err.topupUrl,
|
|
106
|
+
}, null, 2) +
|
|
107
|
+
"\n```",
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
isError: false,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// 5xx + network errors are recoverable; 4xx are not.
|
|
114
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
115
|
+
const recoverable = /\b5\d\d\b|ECONNRESET|ETIMEDOUT|fetch failed|aborted/.test(msg);
|
|
116
|
+
return dualFormatError(name, err, {
|
|
117
|
+
recoverable,
|
|
118
|
+
retryAfterMs: recoverable ? 2000 : undefined,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
// ─── Resources ───────────────────────────────────────────────────────────
|
|
123
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
124
|
+
resources: RESOURCES,
|
|
125
|
+
}));
|
|
126
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
127
|
+
const uri = request.params.uri;
|
|
128
|
+
try {
|
|
129
|
+
const content = await readResource(uri);
|
|
130
|
+
return { contents: [content] };
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
134
|
+
throw new Error(`Failed to read resource ${uri}: ${message}`);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// ─── Prompts ─────────────────────────────────────────────────────────────
|
|
138
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
139
|
+
prompts: PROMPTS,
|
|
140
|
+
}));
|
|
141
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
142
|
+
const { name, arguments: args } = request.params;
|
|
143
|
+
return getPrompt(name, args ?? {});
|
|
144
|
+
});
|
|
145
|
+
// ─── Boot ────────────────────────────────────────────────────────────────
|
|
146
|
+
async function main() {
|
|
147
|
+
const transport = new StdioServerTransport();
|
|
148
|
+
await server.connect(transport);
|
|
149
|
+
// stderr only — stdout is reserved for MCP protocol
|
|
150
|
+
// eslint-disable-next-line no-console
|
|
151
|
+
console.error(`${SERVER_NAME}@${SERVER_VERSION} started on stdio`);
|
|
152
|
+
}
|
|
153
|
+
main().catch((err) => {
|
|
154
|
+
// eslint-disable-next-line no-console
|
|
155
|
+
console.error("Fatal error:", err);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
});
|
|
158
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|