dictionary-mcp 1.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/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # dictionary-mcp
2
+
3
+ Dictionary definitions and word of the day (DictionaryAPI).
4
+
5
+ A merged MCP server that consolidates duplicate single-purpose servers in this monorepo into one focused server.
6
+
7
+ ## Tools
8
+
9
+ - `define` — Definition of a word.
10
+ - `wordOfDay` — Random word with definition.
11
+ - `randomWord` — Another random word with definition.
12
+ - `featuredWord` — Featured word of the day.
13
+
14
+ ## Run
15
+
16
+ ```bash
17
+ npm install
18
+ npm run build
19
+ node dist/index.js
20
+ ```
21
+
22
+ ## Source
23
+
24
+ Public free APIs only. See `src/api.ts` for exact endpoints.
package/dist/api.js ADDED
@@ -0,0 +1,87 @@
1
+ const m0 = (() => {
2
+ const BASE = "https://api.dictionaryapi.dev/api/v2/entries/en";
3
+ const UA = "mrfentmen-dictionary-mcp/1.0 (https://github.com/mrfentmen)";
4
+ class DictError extends Error {
5
+ }
6
+ async function get(url) {
7
+ const res = await fetch(url, { headers: { "User-Agent": UA }, signal: AbortSignal.timeout(20000) });
8
+ if (res.status === 404)
9
+ throw new DictError("Word not found");
10
+ if (!res.ok)
11
+ throw new DictError(`Dictionary error ${res.status}`);
12
+ return (await res.json());
13
+ }
14
+ async function define(args) {
15
+ const word = (args.word ?? "").trim();
16
+ if (!word)
17
+ throw new DictError("Provide a word");
18
+ const d = await get(`${BASE}/${encodeURIComponent(word)}`);
19
+ const entry = d[0] ?? {};
20
+ const phonetics = (entry.phonetics ?? []).map((p) => p.text).filter(Boolean).join(", ");
21
+ const meanings = (entry.meanings ?? []).slice(0, 3).map((m) => {
22
+ const defs = (m.definitions ?? []).slice(0, 3).map((df, i) => `${i + 1}. ${df.definition ?? ""}${df.example ? ` (e.g. ${df.example})` : ""}`).join("\n ");
23
+ return `${m.partOfSpeech ?? ""}\n ${defs}`;
24
+ }).join("\n");
25
+ return `${entry.word ?? word}\n${phonetics ? `Phonetics: ${phonetics}\n` : ""}${meanings || "No definitions"}`;
26
+ }
27
+ async function wordOfDay(_args) {
28
+ const d = await get(`${BASE}/random`);
29
+ const entry = d[0] ?? {};
30
+ const meanings = (entry.meanings ?? []).slice(0, 2).map((m) => {
31
+ const defs = (m.definitions ?? []).slice(0, 2).map((df) => df.definition ?? "").join("; ");
32
+ return `${m.partOfSpeech ?? ""}: ${defs}`;
33
+ }).join("\n");
34
+ return `Word: ${entry.word ?? ""}\n${meanings || "No definitions"}`;
35
+ }
36
+ return { DictError, define, wordOfDay };
37
+ })();
38
+ const m1 = (() => {
39
+ const BASE = "https://api.dictionaryapi.dev/api/v2/entries/en";
40
+ const UA = "mrfentmen-word-of-day-mcp/1.0 (https://github.com/mrfentmen)";
41
+ class WordError extends Error {
42
+ }
43
+ async function get(url) {
44
+ const res = await fetch(url, { headers: { "User-Agent": UA }, signal: AbortSignal.timeout(20000) });
45
+ if (res.status === 404)
46
+ throw new WordError("No word available right now");
47
+ if (!res.ok)
48
+ throw new WordError(`Dictionary error ${res.status}`);
49
+ return (await res.json());
50
+ }
51
+ // Deterministic word pick per UTC day from a curated list, then fetch its real definition.
52
+ const WORDS = ["serendipity", "ephemeral", "luminous", "resilient", "eloquent", "meticulous", "curiosity", "zenith", "quintessential", "effervescent", "solstice", "wanderlust", "euphoria", "tranquil", "vibrant"];
53
+ function wordForToday() {
54
+ const day = Math.floor(Date.now() / 86400000);
55
+ return WORDS[day % WORDS.length];
56
+ }
57
+ async function wordOfTheDay(_args) {
58
+ const word = wordForToday();
59
+ const d = await get(`${BASE}/${word}`);
60
+ const entry = d[0] ?? {};
61
+ const phonetic = (entry.phonetics ?? []).map((p) => p.text).filter(Boolean)[0] ?? "";
62
+ const meaning = (entry.meanings ?? [])[0] ?? {};
63
+ const firstDef = (meaning.definitions ?? [])[0]?.definition ?? "";
64
+ const example = (meaning.definitions ?? [])[0]?.example;
65
+ return `Word of the day: ${entry.word ?? word}\n${phonetic ? `Pronunciation: ${phonetic}\n` : ""}${meaning.partOfSpeech ? `Part of speech: ${meaning.partOfSpeech}\n` : ""}Definition: ${firstDef}${example ? `\nExample: ${example}` : ""}`;
66
+ }
67
+ async function randomWord(_args) {
68
+ const d = await get(`${BASE}/random`);
69
+ const entry = d[0] ?? {};
70
+ const meaning = (entry.meanings ?? [])[0] ?? {};
71
+ const firstDef = (meaning.definitions ?? [])[0]?.definition ?? "";
72
+ return `${entry.word ?? "word"}\n${meaning.partOfSpeech ?? ""}: ${firstDef}`;
73
+ }
74
+ return { WordError, randomWord, wordOfTheDay };
75
+ })();
76
+ export const DictError = m0.DictError;
77
+ export const WordError = m1.WordError;
78
+ export const define = m0.define;
79
+ export const randomWord = m1.randomWord;
80
+ export const wordOfDay = m0.wordOfDay;
81
+ export const wordOfTheDay = m1.wordOfTheDay;
82
+ export const m0_DictError = m0.DictError;
83
+ export const m0_wordOfDay = m0.wordOfDay;
84
+ export const m0_define = m0.define;
85
+ export const m1_wordOfTheDay = m1.wordOfTheDay;
86
+ export const m1_WordError = m1.WordError;
87
+ export const m1_randomWord = m1.randomWord;
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { createServer } from "./server.js";
3
+ const main = async () => { const server = createServer(); await server.connect(new StdioServerTransport()); };
4
+ main().catch((error) => { console.error("Fatal error:", error); process.exit(1); });
package/dist/server.js ADDED
@@ -0,0 +1,64 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod';
3
+ import { m0_define, m0_wordOfDay, m1_randomWord, m1_wordOfTheDay } from './api.js';
4
+ const text = (value) => ({ content: [{ type: 'text', text: value }] });
5
+ const textError = (t) => ({ content: [{ type: "text", text: t }], isError: true });
6
+ const READ_ONLY = { readOnlyHint: true, openWorldHint: true };
7
+ const error = (e) => `Error: ${e instanceof Error ? e.message : String(e)}`;
8
+ const errorMessage = error;
9
+ export function createServer() {
10
+ const server = new McpServer({ name: 'dictionary-mcp', version: '1.0.0' });
11
+ server.registerTool("define", {
12
+ title: "Define",
13
+ description: "Get the definition of a word.",
14
+ inputSchema: z.object({ word: z.string().describe("Word to look up.") }),
15
+ annotations: READ_ONLY,
16
+ }, async (args) => {
17
+ try {
18
+ return text(await m0_define(args));
19
+ }
20
+ catch (e) {
21
+ return textError(error(e));
22
+ }
23
+ });
24
+ server.registerTool("word_of_day", {
25
+ title: "Word of day",
26
+ description: "Get a random word with its definition.",
27
+ inputSchema: z.object({}),
28
+ annotations: READ_ONLY,
29
+ }, async (args) => {
30
+ try {
31
+ return text(await m0_wordOfDay(args));
32
+ }
33
+ catch (e) {
34
+ return textError(error(e));
35
+ }
36
+ });
37
+ server.registerTool("word_of_the_day", {
38
+ title: "Word of the day",
39
+ description: "Get the featured word of the day.",
40
+ inputSchema: z.object({}),
41
+ annotations: READ_ONLY,
42
+ }, async (args) => {
43
+ try {
44
+ return text(await m1_wordOfTheDay(args));
45
+ }
46
+ catch (e) {
47
+ return textError(error(e));
48
+ }
49
+ });
50
+ server.registerTool("random_word", {
51
+ title: "Random word",
52
+ description: "Get a random word with its definition.",
53
+ inputSchema: z.object({}),
54
+ annotations: READ_ONLY,
55
+ }, async (args) => {
56
+ try {
57
+ return text(await m1_randomWord(args));
58
+ }
59
+ catch (e) {
60
+ return textError(error(e));
61
+ }
62
+ });
63
+ return server;
64
+ }
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "dictionary-mcp",
3
+ "version": "1.0.0",
4
+ "description": "Dictionary definitions and word of the day (DictionaryAPI).",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "build": "tsc -p tsconfig.json",
9
+ "start": "node dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@modelcontextprotocol/sdk": "^1.0.0",
13
+ "zod": "^3.23.0"
14
+ },
15
+ "devDependencies": {
16
+ "typescript": "^5.5.0",
17
+ "@types/node": "^20.0.0"
18
+ },
19
+ "license": "MIT",
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "mcpName": "io.github.mrfentmen/dictionary-mcp"
24
+ }
package/server.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.mrfentmen/dictionary-mcp",
4
+ "description": "Dictionary definitions and word of the day (DictionaryAPI).",
5
+ "repository": {
6
+ "url": "https://github.com/mrfentmen/awesome-mcps",
7
+ "source": "github"
8
+ },
9
+ "version": "1.0.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "dictionary-mcp",
14
+ "version": "1.0.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ }
18
+ }
19
+ ]
20
+ }
package/src/api.ts ADDED
@@ -0,0 +1,92 @@
1
+ const m0 = (() => {
2
+ const BASE = "https://api.dictionaryapi.dev/api/v2/entries/en"
3
+ const UA = "mrfentmen-dictionary-mcp/1.0 (https://github.com/mrfentmen)"
4
+ class DictError extends Error {}
5
+
6
+ async function get<T>(url: string): Promise<T> {
7
+ const res = await fetch(url, { headers: { "User-Agent": UA }, signal: AbortSignal.timeout(20000) })
8
+ if (res.status === 404) throw new DictError("Word not found")
9
+ if (!res.ok) throw new DictError(`Dictionary error ${res.status}`)
10
+ return (await res.json()) as T
11
+ }
12
+
13
+ async function define(args: { word?: string }): Promise<string> {
14
+ const word = (args.word ?? "").trim()
15
+ if (!word) throw new DictError("Provide a word")
16
+ const d = await get<any[]>(`${BASE}/${encodeURIComponent(word)}`)
17
+ const entry = d[0] ?? {}
18
+ const phonetics = (entry.phonetics ?? []).map((p: any) => p.text).filter(Boolean).join(", ")
19
+ const meanings = (entry.meanings ?? []).slice(0, 3).map((m: any) => {
20
+ const defs = (m.definitions ?? []).slice(0, 3).map((df: any, i: number) => `${i + 1}. ${df.definition ?? ""}${df.example ? ` (e.g. ${df.example})` : ""}`).join("\n ")
21
+ return `${m.partOfSpeech ?? ""}\n ${defs}`
22
+ }).join("\n")
23
+ return `${entry.word ?? word}\n${phonetics ? `Phonetics: ${phonetics}\n` : ""}${meanings || "No definitions"}`
24
+ }
25
+
26
+ async function wordOfDay(_args: Record<string, never>): Promise<string> {
27
+ const d = await get<any[]>(`${BASE}/random`)
28
+ const entry = d[0] ?? {}
29
+ const meanings = (entry.meanings ?? []).slice(0, 2).map((m: any) => {
30
+ const defs = (m.definitions ?? []).slice(0, 2).map((df: any) => df.definition ?? "").join("; ")
31
+ return `${m.partOfSpeech ?? ""}: ${defs}`
32
+ }).join("\n")
33
+ return `Word: ${entry.word ?? ""}\n${meanings || "No definitions"}`
34
+ }
35
+
36
+ return { DictError, define, wordOfDay };
37
+ })();
38
+
39
+ const m1 = (() => {
40
+ const BASE = "https://api.dictionaryapi.dev/api/v2/entries/en"
41
+ const UA = "mrfentmen-word-of-day-mcp/1.0 (https://github.com/mrfentmen)"
42
+ class WordError extends Error {}
43
+
44
+ async function get<T>(url: string): Promise<T> {
45
+ const res = await fetch(url, { headers: { "User-Agent": UA }, signal: AbortSignal.timeout(20000) })
46
+ if (res.status === 404) throw new WordError("No word available right now")
47
+ if (!res.ok) throw new WordError(`Dictionary error ${res.status}`)
48
+ return (await res.json()) as T
49
+ }
50
+
51
+ // Deterministic word pick per UTC day from a curated list, then fetch its real definition.
52
+ const WORDS = ["serendipity", "ephemeral", "luminous", "resilient", "eloquent", "meticulous", "curiosity", "zenith", "quintessential", "effervescent", "solstice", "wanderlust", "euphoria", "tranquil", "vibrant"]
53
+
54
+ function wordForToday(): string {
55
+ const day = Math.floor(Date.now() / 86400000)
56
+ return WORDS[day % WORDS.length]
57
+ }
58
+
59
+ async function wordOfTheDay(_args: Record<string, never>): Promise<string> {
60
+ const word = wordForToday()
61
+ const d = await get<any[]>(`${BASE}/${word}`)
62
+ const entry = d[0] ?? {}
63
+ const phonetic = (entry.phonetics ?? []).map((p: any) => p.text).filter(Boolean)[0] ?? ""
64
+ const meaning = (entry.meanings ?? [])[0] ?? {}
65
+ const firstDef = (meaning.definitions ?? [])[0]?.definition ?? ""
66
+ const example = (meaning.definitions ?? [])[0]?.example
67
+ return `Word of the day: ${entry.word ?? word}\n${phonetic ? `Pronunciation: ${phonetic}\n` : ""}${meaning.partOfSpeech ? `Part of speech: ${meaning.partOfSpeech}\n` : ""}Definition: ${firstDef}${example ? `\nExample: ${example}` : ""}`
68
+ }
69
+
70
+ async function randomWord(_args: Record<string, never>): Promise<string> {
71
+ const d = await get<any[]>(`${BASE}/random`)
72
+ const entry = d[0] ?? {}
73
+ const meaning = (entry.meanings ?? [])[0] ?? {}
74
+ const firstDef = (meaning.definitions ?? [])[0]?.definition ?? ""
75
+ return `${entry.word ?? "word"}\n${meaning.partOfSpeech ?? ""}: ${firstDef}`
76
+ }
77
+
78
+ return { WordError, randomWord, wordOfTheDay };
79
+ })();
80
+
81
+ export const DictError = m0.DictError;
82
+ export const WordError = m1.WordError;
83
+ export const define = m0.define;
84
+ export const randomWord = m1.randomWord;
85
+ export const wordOfDay = m0.wordOfDay;
86
+ export const wordOfTheDay = m1.wordOfTheDay;
87
+ export const m0_DictError = m0.DictError;
88
+ export const m0_wordOfDay = m0.wordOfDay;
89
+ export const m0_define = m0.define;
90
+ export const m1_wordOfTheDay = m1.wordOfTheDay;
91
+ export const m1_WordError = m1.WordError;
92
+ export const m1_randomWord = m1.randomWord;
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
2
+ import { createServer } from "./server.js"
3
+ const main = async () => { const server = createServer(); await server.connect(new StdioServerTransport()) }
4
+ main().catch((error) => { console.error("Fatal error:", error); process.exit(1) })
package/src/server.ts ADDED
@@ -0,0 +1,62 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
+ import { z } from 'zod'
3
+ import { m0_define, m0_wordOfDay, m1_randomWord, m1_wordOfTheDay } from './api.js'
4
+
5
+ const text = (value: string) => ({ content: [{ type: 'text' as const, text: value }] })
6
+ const textError = (t: string) => ({ content: [{ type: "text" as const, text: t }], isError: true as const })
7
+ const READ_ONLY = { readOnlyHint: true, openWorldHint: true } as const
8
+ const error = (e: unknown) => `Error: ${e instanceof Error ? e.message : String(e)}`
9
+ const errorMessage = error
10
+
11
+ export function createServer(): McpServer {
12
+ const server = new McpServer({ name: 'dictionary-mcp', version: '1.0.0' })
13
+ server.registerTool(
14
+ "define",
15
+ {
16
+ title: "Define",
17
+ description: "Get the definition of a word.",
18
+ inputSchema: z.object( { word: z.string().describe("Word to look up.") }),
19
+ annotations: READ_ONLY,
20
+ },
21
+ async (args) => {
22
+ try { return text(await m0_define(args)) } catch (e) { return textError(error(e)) }
23
+ }
24
+ )
25
+ server.registerTool(
26
+ "word_of_day",
27
+ {
28
+ title: "Word of day",
29
+ description: "Get a random word with its definition.",
30
+ inputSchema: z.object( { }),
31
+ annotations: READ_ONLY,
32
+ },
33
+ async (args) => {
34
+ try { return text(await m0_wordOfDay(args)) } catch (e) { return textError(error(e)) }
35
+ }
36
+ )
37
+ server.registerTool(
38
+ "word_of_the_day",
39
+ {
40
+ title: "Word of the day",
41
+ description: "Get the featured word of the day.",
42
+ inputSchema: z.object( { }),
43
+ annotations: READ_ONLY,
44
+ },
45
+ async (args) => {
46
+ try { return text(await m1_wordOfTheDay(args)) } catch (e) { return textError(error(e)) }
47
+ }
48
+ )
49
+ server.registerTool(
50
+ "random_word",
51
+ {
52
+ title: "Random word",
53
+ description: "Get a random word with its definition.",
54
+ inputSchema: z.object( { }),
55
+ annotations: READ_ONLY,
56
+ },
57
+ async (args) => {
58
+ try { return text(await m1_randomWord(args)) } catch (e) { return textError(error(e)) }
59
+ }
60
+ )
61
+ return server
62
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true
12
+ },
13
+ "include": [
14
+ "src/**/*"
15
+ ]
16
+ }