german-rhymes-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,131 @@
1
+ # German Rhymes MCP Server 🎤
2
+
3
+ An MCP (Model Context Protocol) server that provides German rhyme search capabilities using the [double-rhyme.com](https://double-rhyme.com/) API.
4
+
5
+ ## Features
6
+
7
+ - 🔍 **Find Rhymes**: Search for German rhymes for any word or phrase
8
+ - 🎯 **Double Rhymes**: Support for multi-word phrases (Doppelreime)
9
+ - 📊 **Multiple Match Types**: Exact rhymes, vowel matches, ending rhymes
10
+ - 🚀 **No Authentication Required**: The underlying API needs no API key
11
+ - 💨 **Fast**: Simple GET requests to the API
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ cd rhyme-mcp
17
+ pnpm install
18
+ pnpm build
19
+ ```
20
+
21
+ ## Usage with Cursor
22
+
23
+ Add to your Cursor settings (`~/.cursor/mcp.json` or Cursor Settings → MCP):
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "german-rhymes": {
29
+ "command": "node",
30
+ "args": ["/path/to/rhyme-mcp/dist/index.js"]
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ Or for development:
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "german-rhymes": {
42
+ "command": "npx",
43
+ "args": ["tsx", "/path/to/rhyme-mcp/src/index.ts"]
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## Available Tools
50
+
51
+ ### `find_rhymes`
52
+
53
+ Finds German rhymes for a word or phrase with detailed output.
54
+
55
+ **Parameters:**
56
+ - `word` (required): The word or phrase to find rhymes for
57
+ - `match_type` (optional): Type of matching - `best` (default), `vowel`, or `ending`
58
+ - `limit` (optional): Maximum number of rhymes to return
59
+
60
+ **Example:**
61
+ ```
62
+ Find rhymes for "Liebe"
63
+ Find rhymes for "kiefer knochen" (double rhyme)
64
+ ```
65
+
66
+ ### `find_rhymes_json`
67
+
68
+ Same as `find_rhymes` but returns JSON output for programmatic use.
69
+
70
+ ### `quick_rhymes`
71
+
72
+ Quick rhyme suggestions - returns only the best rhymes as a simple list.
73
+
74
+ **Parameters:**
75
+ - `word` (required): The word to find rhymes for
76
+ - `count` (optional): Number of rhymes (default: 10)
77
+
78
+ ## Example Output
79
+
80
+ ```
81
+ 🎤 Reime für "Haus"
82
+
83
+ Gefunden: 48 Reime insgesamt
84
+
85
+ ✨ **Exakte Reime** (10):
86
+ aus, raus, draus, maus, baus, strauß, graus, braus, staus, blaus
87
+
88
+ 🎯 **Kuratierte Reime** (3):
89
+ schmaus, laus, kraus
90
+
91
+ 📝 **Ähnliche Reime** (15):
92
+ applaus, voraus, hinaus, heraus, daraus, durchaus, hieraus...
93
+
94
+ 🔊 **Vokal-Übereinstimmungen** (20):
95
+ auf, auch, drauf, glaub, schau, sound, faust, raum...
96
+ ```
97
+
98
+ ## Development
99
+
100
+ ```bash
101
+ # Run in development mode
102
+ pnpm dev
103
+
104
+ # Build for production
105
+ pnpm build
106
+
107
+ # Watch mode
108
+ pnpm watch
109
+ ```
110
+
111
+ ## API Reference
112
+
113
+ This MCP server uses the double-rhyme.com API:
114
+
115
+ ```
116
+ GET https://us-central1-double-rhyme-website.cloudfunctions.net/rhyme-proxy
117
+ ?searchterm=<word>
118
+ &language=de
119
+ &matchType=vowel_rhyme_consonantal_ending
120
+ &genre=rap
121
+ ```
122
+
123
+ **Match Types:**
124
+ - `vowel_rhyme_consonantal_ending` - Best for rap/poetry
125
+ - `vowel_rhyme` - Vowel sound matches only
126
+ - `ending_rhyme` - Traditional end rhymes
127
+
128
+ ## License
129
+
130
+ MIT
131
+
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,228 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ // API Configuration
6
+ const API_URL = "https://us-central1-double-rhyme-website.cloudfunctions.net/rhyme-proxy";
7
+ /**
8
+ * Fetch rhymes from the double-rhyme.com API
9
+ */
10
+ async function fetchRhymes(searchTerm, matchType = "vowel_rhyme_consonantal_ending") {
11
+ const params = new URLSearchParams({
12
+ searchterm: searchTerm,
13
+ language: "de",
14
+ matchType,
15
+ genre: "rap",
16
+ });
17
+ const response = await fetch(`${API_URL}?${params}`);
18
+ if (!response.ok) {
19
+ throw new Error(`API request failed: ${response.status} ${response.statusText}`);
20
+ }
21
+ const data = await response.json();
22
+ if (data.errors) {
23
+ throw new Error(`API error: ${data.errors}`);
24
+ }
25
+ const results = data.typeToResultMap || {};
26
+ const exactRhymes = results.ending2 || [];
27
+ const closeRhymes = results.ending1 || [];
28
+ const vowelMatches = results.v || [];
29
+ const curatedRhymes = results.custom || [];
30
+ const userSubmitted = results.user || [];
31
+ // Combine all rhymes and deduplicate
32
+ const allRhymes = [...new Set([
33
+ ...exactRhymes,
34
+ ...curatedRhymes,
35
+ ...closeRhymes,
36
+ ...vowelMatches,
37
+ ...userSubmitted,
38
+ ])];
39
+ return {
40
+ exactRhymes,
41
+ closeRhymes,
42
+ vowelMatches,
43
+ curatedRhymes,
44
+ userSubmitted,
45
+ allRhymes,
46
+ };
47
+ }
48
+ /**
49
+ * Format rhyme results for display
50
+ */
51
+ function formatRhymeResults(word, results) {
52
+ const sections = [];
53
+ sections.push(`🎤 Reime für "${word}"\n`);
54
+ sections.push(`Gefunden: ${results.allRhymes.length} Reime insgesamt\n`);
55
+ if (results.exactRhymes.length > 0) {
56
+ sections.push(`\n✨ **Exakte Reime** (${results.exactRhymes.length}):`);
57
+ sections.push(results.exactRhymes.slice(0, 20).join(", "));
58
+ if (results.exactRhymes.length > 20) {
59
+ sections.push(`... und ${results.exactRhymes.length - 20} weitere`);
60
+ }
61
+ }
62
+ if (results.curatedRhymes.length > 0) {
63
+ sections.push(`\n🎯 **Kuratierte Reime** (${results.curatedRhymes.length}):`);
64
+ sections.push(results.curatedRhymes.slice(0, 15).join(", "));
65
+ }
66
+ if (results.closeRhymes.length > 0) {
67
+ sections.push(`\n📝 **Ähnliche Reime** (${results.closeRhymes.length}):`);
68
+ sections.push(results.closeRhymes.slice(0, 15).join(", "));
69
+ if (results.closeRhymes.length > 15) {
70
+ sections.push(`... und ${results.closeRhymes.length - 15} weitere`);
71
+ }
72
+ }
73
+ if (results.vowelMatches.length > 0) {
74
+ sections.push(`\n🔊 **Vokal-Übereinstimmungen** (${results.vowelMatches.length}):`);
75
+ sections.push(results.vowelMatches.slice(0, 20).join(", "));
76
+ if (results.vowelMatches.length > 20) {
77
+ sections.push(`... und ${results.vowelMatches.length - 20} weitere`);
78
+ }
79
+ }
80
+ if (results.userSubmitted.length > 0) {
81
+ sections.push(`\n👥 **Community Reime** (${results.userSubmitted.length}):`);
82
+ sections.push(results.userSubmitted.slice(0, 10).join(", "));
83
+ }
84
+ return sections.join("\n");
85
+ }
86
+ // Create the MCP server
87
+ const server = new McpServer({
88
+ name: "german-rhymes",
89
+ version: "1.0.0",
90
+ });
91
+ // Register the rhyme search tool
92
+ server.tool("find_rhymes", "Findet deutsche Reime für ein Wort oder eine Phrase. Unterstützt auch Doppelreime (mehrere Wörter).", {
93
+ word: z.string().describe("Das Wort oder die Phrase, für die Reime gesucht werden sollen"),
94
+ match_type: z.enum(["best", "vowel", "ending"]).optional().describe("Art der Reim-Übereinstimmung: 'best' (Standard, beste Ergebnisse), 'vowel' (nur Vokalübereinstimmung), 'ending' (nur Endreime)"),
95
+ limit: z.number().optional().describe("Maximale Anzahl der zurückgegebenen Reime (Standard: alle)"),
96
+ }, async ({ word, match_type, limit }) => {
97
+ try {
98
+ // Map match_type to API matchType
99
+ const matchTypeMap = {
100
+ best: "vowel_rhyme_consonantal_ending",
101
+ vowel: "vowel_rhyme",
102
+ ending: "ending_rhyme",
103
+ };
104
+ const apiMatchType = matchTypeMap[match_type || "best"] || "vowel_rhyme_consonantal_ending";
105
+ const results = await fetchRhymes(word, apiMatchType);
106
+ // Apply limit if specified
107
+ if (limit && limit > 0) {
108
+ results.allRhymes = results.allRhymes.slice(0, limit);
109
+ results.exactRhymes = results.exactRhymes.slice(0, Math.ceil(limit / 3));
110
+ results.vowelMatches = results.vowelMatches.slice(0, Math.ceil(limit / 3));
111
+ results.closeRhymes = results.closeRhymes.slice(0, Math.ceil(limit / 3));
112
+ }
113
+ const formattedOutput = formatRhymeResults(word, results);
114
+ return {
115
+ content: [
116
+ {
117
+ type: "text",
118
+ text: formattedOutput,
119
+ },
120
+ ],
121
+ };
122
+ }
123
+ catch (error) {
124
+ const errorMessage = error instanceof Error ? error.message : "Unbekannter Fehler";
125
+ return {
126
+ content: [
127
+ {
128
+ type: "text",
129
+ text: `❌ Fehler beim Suchen von Reimen für "${word}": ${errorMessage}`,
130
+ },
131
+ ],
132
+ isError: true,
133
+ };
134
+ }
135
+ });
136
+ // Register a tool to get rhymes as JSON (for programmatic use)
137
+ server.tool("find_rhymes_json", "Findet deutsche Reime und gibt sie als JSON zurück (für programmatische Verwendung).", {
138
+ word: z.string().describe("Das Wort oder die Phrase, für die Reime gesucht werden sollen"),
139
+ match_type: z.enum(["best", "vowel", "ending"]).optional().describe("Art der Reim-Übereinstimmung"),
140
+ }, async ({ word, match_type }) => {
141
+ try {
142
+ const matchTypeMap = {
143
+ best: "vowel_rhyme_consonantal_ending",
144
+ vowel: "vowel_rhyme",
145
+ ending: "ending_rhyme",
146
+ };
147
+ const apiMatchType = matchTypeMap[match_type || "best"] || "vowel_rhyme_consonantal_ending";
148
+ const results = await fetchRhymes(word, apiMatchType);
149
+ return {
150
+ content: [
151
+ {
152
+ type: "text",
153
+ text: JSON.stringify({
154
+ query: word,
155
+ matchType: match_type || "best",
156
+ results: {
157
+ exactRhymes: results.exactRhymes,
158
+ closeRhymes: results.closeRhymes,
159
+ vowelMatches: results.vowelMatches,
160
+ curatedRhymes: results.curatedRhymes,
161
+ userSubmitted: results.userSubmitted,
162
+ total: results.allRhymes.length,
163
+ },
164
+ }, null, 2),
165
+ },
166
+ ],
167
+ };
168
+ }
169
+ catch (error) {
170
+ const errorMessage = error instanceof Error ? error.message : "Unbekannter Fehler";
171
+ return {
172
+ content: [
173
+ {
174
+ type: "text",
175
+ text: JSON.stringify({ error: errorMessage, query: word }, null, 2),
176
+ },
177
+ ],
178
+ isError: true,
179
+ };
180
+ }
181
+ });
182
+ // Register a tool for quick rhyme suggestions (concise output)
183
+ server.tool("quick_rhymes", "Schnelle Reim-Vorschläge - gibt nur die besten Reime als Liste zurück.", {
184
+ word: z.string().describe("Das Wort für das Reime gesucht werden"),
185
+ count: z.number().optional().describe("Anzahl der Reime (Standard: 10)"),
186
+ }, async ({ word, count }) => {
187
+ try {
188
+ const results = await fetchRhymes(word);
189
+ const limit = count || 10;
190
+ // Get the best rhymes (prioritize exact, then curated, then close)
191
+ const bestRhymes = [
192
+ ...results.exactRhymes,
193
+ ...results.curatedRhymes,
194
+ ...results.closeRhymes,
195
+ ].slice(0, limit);
196
+ return {
197
+ content: [
198
+ {
199
+ type: "text",
200
+ text: `Reime für "${word}": ${bestRhymes.join(", ")}`,
201
+ },
202
+ ],
203
+ };
204
+ }
205
+ catch (error) {
206
+ const errorMessage = error instanceof Error ? error.message : "Unbekannter Fehler";
207
+ return {
208
+ content: [
209
+ {
210
+ type: "text",
211
+ text: `Fehler: ${errorMessage}`,
212
+ },
213
+ ],
214
+ isError: true,
215
+ };
216
+ }
217
+ });
218
+ // Main function to start the server
219
+ async function main() {
220
+ const transport = new StdioServerTransport();
221
+ await server.connect(transport);
222
+ console.error("German Rhymes MCP Server running on stdio");
223
+ }
224
+ main().catch((error) => {
225
+ console.error("Failed to start server:", error);
226
+ process.exit(1);
227
+ });
228
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "german-rhymes-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for finding German rhymes using double-rhyme.com API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "german-rhymes-mcp": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js",
13
+ "dev": "tsx src/index.ts",
14
+ "watch": "tsc --watch"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "rhymes",
19
+ "german",
20
+ "poetry",
21
+ "rap"
22
+ ],
23
+ "author": "",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "@modelcontextprotocol/sdk": "^1.0.0",
27
+ "zod": "^3.23.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^20.0.0",
31
+ "tsx": "^4.0.0",
32
+ "typescript": "^5.0.0"
33
+ },
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ }
37
+ }
38
+
package/src/index.ts ADDED
@@ -0,0 +1,304 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+
7
+ // Types for the API response
8
+ interface RhymeApiResponse {
9
+ typeToResultMap: {
10
+ ending2?: string[]; // Best exact rhymes
11
+ ending1?: string[]; // Close ending matches
12
+ v?: string[]; // Vowel sound matches
13
+ custom?: string[]; // Curated rhymes
14
+ user?: string[]; // User-submitted rhymes
15
+ };
16
+ requestType: string;
17
+ errors: string | null;
18
+ }
19
+
20
+ interface RhymeResult {
21
+ exactRhymes: string[];
22
+ closeRhymes: string[];
23
+ vowelMatches: string[];
24
+ curatedRhymes: string[];
25
+ userSubmitted: string[];
26
+ allRhymes: string[];
27
+ }
28
+
29
+ // API Configuration
30
+ const API_URL = "https://us-central1-double-rhyme-website.cloudfunctions.net/rhyme-proxy";
31
+
32
+ type MatchType = "vowel_rhyme_consonantal_ending" | "vowel_rhyme" | "ending_rhyme";
33
+
34
+ /**
35
+ * Fetch rhymes from the double-rhyme.com API
36
+ */
37
+ async function fetchRhymes(
38
+ searchTerm: string,
39
+ matchType: MatchType = "vowel_rhyme_consonantal_ending"
40
+ ): Promise<RhymeResult> {
41
+ const params = new URLSearchParams({
42
+ searchterm: searchTerm,
43
+ language: "de",
44
+ matchType,
45
+ genre: "rap",
46
+ });
47
+
48
+ const response = await fetch(`${API_URL}?${params}`);
49
+
50
+ if (!response.ok) {
51
+ throw new Error(`API request failed: ${response.status} ${response.statusText}`);
52
+ }
53
+
54
+ const data: RhymeApiResponse = await response.json();
55
+
56
+ if (data.errors) {
57
+ throw new Error(`API error: ${data.errors}`);
58
+ }
59
+
60
+ const results = data.typeToResultMap || {};
61
+
62
+ const exactRhymes = results.ending2 || [];
63
+ const closeRhymes = results.ending1 || [];
64
+ const vowelMatches = results.v || [];
65
+ const curatedRhymes = results.custom || [];
66
+ const userSubmitted = results.user || [];
67
+
68
+ // Combine all rhymes and deduplicate
69
+ const allRhymes = [...new Set([
70
+ ...exactRhymes,
71
+ ...curatedRhymes,
72
+ ...closeRhymes,
73
+ ...vowelMatches,
74
+ ...userSubmitted,
75
+ ])];
76
+
77
+ return {
78
+ exactRhymes,
79
+ closeRhymes,
80
+ vowelMatches,
81
+ curatedRhymes,
82
+ userSubmitted,
83
+ allRhymes,
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Format rhyme results for display
89
+ */
90
+ function formatRhymeResults(word: string, results: RhymeResult): string {
91
+ const sections: string[] = [];
92
+
93
+ sections.push(`🎤 Reime für "${word}"\n`);
94
+ sections.push(`Gefunden: ${results.allRhymes.length} Reime insgesamt\n`);
95
+
96
+ if (results.exactRhymes.length > 0) {
97
+ sections.push(`\n✨ **Exakte Reime** (${results.exactRhymes.length}):`);
98
+ sections.push(results.exactRhymes.slice(0, 20).join(", "));
99
+ if (results.exactRhymes.length > 20) {
100
+ sections.push(`... und ${results.exactRhymes.length - 20} weitere`);
101
+ }
102
+ }
103
+
104
+ if (results.curatedRhymes.length > 0) {
105
+ sections.push(`\n🎯 **Kuratierte Reime** (${results.curatedRhymes.length}):`);
106
+ sections.push(results.curatedRhymes.slice(0, 15).join(", "));
107
+ }
108
+
109
+ if (results.closeRhymes.length > 0) {
110
+ sections.push(`\n📝 **Ähnliche Reime** (${results.closeRhymes.length}):`);
111
+ sections.push(results.closeRhymes.slice(0, 15).join(", "));
112
+ if (results.closeRhymes.length > 15) {
113
+ sections.push(`... und ${results.closeRhymes.length - 15} weitere`);
114
+ }
115
+ }
116
+
117
+ if (results.vowelMatches.length > 0) {
118
+ sections.push(`\n🔊 **Vokal-Übereinstimmungen** (${results.vowelMatches.length}):`);
119
+ sections.push(results.vowelMatches.slice(0, 20).join(", "));
120
+ if (results.vowelMatches.length > 20) {
121
+ sections.push(`... und ${results.vowelMatches.length - 20} weitere`);
122
+ }
123
+ }
124
+
125
+ if (results.userSubmitted.length > 0) {
126
+ sections.push(`\n👥 **Community Reime** (${results.userSubmitted.length}):`);
127
+ sections.push(results.userSubmitted.slice(0, 10).join(", "));
128
+ }
129
+
130
+ return sections.join("\n");
131
+ }
132
+
133
+ // Create the MCP server
134
+ const server = new McpServer({
135
+ name: "german-rhymes",
136
+ version: "1.0.0",
137
+ });
138
+
139
+ // Register the rhyme search tool
140
+ server.tool(
141
+ "find_rhymes",
142
+ "Findet deutsche Reime für ein Wort oder eine Phrase. Unterstützt auch Doppelreime (mehrere Wörter).",
143
+ {
144
+ word: z.string().describe("Das Wort oder die Phrase, für die Reime gesucht werden sollen"),
145
+ match_type: z.enum(["best", "vowel", "ending"]).optional().describe(
146
+ "Art der Reim-Übereinstimmung: 'best' (Standard, beste Ergebnisse), 'vowel' (nur Vokalübereinstimmung), 'ending' (nur Endreime)"
147
+ ),
148
+ limit: z.number().optional().describe("Maximale Anzahl der zurückgegebenen Reime (Standard: alle)"),
149
+ },
150
+ async ({ word, match_type, limit }) => {
151
+ try {
152
+ // Map match_type to API matchType
153
+ const matchTypeMap: Record<string, MatchType> = {
154
+ best: "vowel_rhyme_consonantal_ending",
155
+ vowel: "vowel_rhyme",
156
+ ending: "ending_rhyme",
157
+ };
158
+
159
+ const apiMatchType = matchTypeMap[match_type || "best"] || "vowel_rhyme_consonantal_ending";
160
+
161
+ const results = await fetchRhymes(word, apiMatchType);
162
+
163
+ // Apply limit if specified
164
+ if (limit && limit > 0) {
165
+ results.allRhymes = results.allRhymes.slice(0, limit);
166
+ results.exactRhymes = results.exactRhymes.slice(0, Math.ceil(limit / 3));
167
+ results.vowelMatches = results.vowelMatches.slice(0, Math.ceil(limit / 3));
168
+ results.closeRhymes = results.closeRhymes.slice(0, Math.ceil(limit / 3));
169
+ }
170
+
171
+ const formattedOutput = formatRhymeResults(word, results);
172
+
173
+ return {
174
+ content: [
175
+ {
176
+ type: "text" as const,
177
+ text: formattedOutput,
178
+ },
179
+ ],
180
+ };
181
+ } catch (error) {
182
+ const errorMessage = error instanceof Error ? error.message : "Unbekannter Fehler";
183
+ return {
184
+ content: [
185
+ {
186
+ type: "text" as const,
187
+ text: `❌ Fehler beim Suchen von Reimen für "${word}": ${errorMessage}`,
188
+ },
189
+ ],
190
+ isError: true,
191
+ };
192
+ }
193
+ }
194
+ );
195
+
196
+ // Register a tool to get rhymes as JSON (for programmatic use)
197
+ server.tool(
198
+ "find_rhymes_json",
199
+ "Findet deutsche Reime und gibt sie als JSON zurück (für programmatische Verwendung).",
200
+ {
201
+ word: z.string().describe("Das Wort oder die Phrase, für die Reime gesucht werden sollen"),
202
+ match_type: z.enum(["best", "vowel", "ending"]).optional().describe("Art der Reim-Übereinstimmung"),
203
+ },
204
+ async ({ word, match_type }) => {
205
+ try {
206
+ const matchTypeMap: Record<string, MatchType> = {
207
+ best: "vowel_rhyme_consonantal_ending",
208
+ vowel: "vowel_rhyme",
209
+ ending: "ending_rhyme",
210
+ };
211
+
212
+ const apiMatchType = matchTypeMap[match_type || "best"] || "vowel_rhyme_consonantal_ending";
213
+
214
+ const results = await fetchRhymes(word, apiMatchType);
215
+
216
+ return {
217
+ content: [
218
+ {
219
+ type: "text" as const,
220
+ text: JSON.stringify({
221
+ query: word,
222
+ matchType: match_type || "best",
223
+ results: {
224
+ exactRhymes: results.exactRhymes,
225
+ closeRhymes: results.closeRhymes,
226
+ vowelMatches: results.vowelMatches,
227
+ curatedRhymes: results.curatedRhymes,
228
+ userSubmitted: results.userSubmitted,
229
+ total: results.allRhymes.length,
230
+ },
231
+ }, null, 2),
232
+ },
233
+ ],
234
+ };
235
+ } catch (error) {
236
+ const errorMessage = error instanceof Error ? error.message : "Unbekannter Fehler";
237
+ return {
238
+ content: [
239
+ {
240
+ type: "text" as const,
241
+ text: JSON.stringify({ error: errorMessage, query: word }, null, 2),
242
+ },
243
+ ],
244
+ isError: true,
245
+ };
246
+ }
247
+ }
248
+ );
249
+
250
+ // Register a tool for quick rhyme suggestions (concise output)
251
+ server.tool(
252
+ "quick_rhymes",
253
+ "Schnelle Reim-Vorschläge - gibt nur die besten Reime als Liste zurück.",
254
+ {
255
+ word: z.string().describe("Das Wort für das Reime gesucht werden"),
256
+ count: z.number().optional().describe("Anzahl der Reime (Standard: 10)"),
257
+ },
258
+ async ({ word, count }) => {
259
+ try {
260
+ const results = await fetchRhymes(word);
261
+ const limit = count || 10;
262
+
263
+ // Get the best rhymes (prioritize exact, then curated, then close)
264
+ const bestRhymes = [
265
+ ...results.exactRhymes,
266
+ ...results.curatedRhymes,
267
+ ...results.closeRhymes,
268
+ ].slice(0, limit);
269
+
270
+ return {
271
+ content: [
272
+ {
273
+ type: "text" as const,
274
+ text: `Reime für "${word}": ${bestRhymes.join(", ")}`,
275
+ },
276
+ ],
277
+ };
278
+ } catch (error) {
279
+ const errorMessage = error instanceof Error ? error.message : "Unbekannter Fehler";
280
+ return {
281
+ content: [
282
+ {
283
+ type: "text" as const,
284
+ text: `Fehler: ${errorMessage}`,
285
+ },
286
+ ],
287
+ isError: true,
288
+ };
289
+ }
290
+ }
291
+ );
292
+
293
+ // Main function to start the server
294
+ async function main() {
295
+ const transport = new StdioServerTransport();
296
+ await server.connect(transport);
297
+ console.error("German Rhymes MCP Server running on stdio");
298
+ }
299
+
300
+ main().catch((error) => {
301
+ console.error("Failed to start server:", error);
302
+ process.exit(1);
303
+ });
304
+
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
19
+