tdk-api-wrapper 1.6.0 → 1.7.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 +21 -1
- package/dist/chunk-MELLECWT.mjs +279 -0
- package/dist/cli.js +2444 -2114
- package/dist/cli.mjs +11 -4
- package/dist/index.d.mts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +277 -2
- package/dist/index.mjs +7 -1
- package/dist/mcp-NAXIX4TQ.mjs +9 -0
- package/package.json +33 -5
- package/.github/workflows/publish.yml +0 -41
- package/src/cli.ts +0 -535
- package/src/errors.ts +0 -38
- package/src/index.ts +0 -4
- package/src/morphology.ts +0 -333
- package/src/tdk.ts +0 -2056
- package/src/types.ts +0 -185
- package/test/grammar.test.js +0 -52
- package/test/morphology.test.js +0 -140
- package/test/proofread.test.js +0 -88
- package/test/tools.test.js +0 -51
- package/tsconfig.json +0 -11
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# TDK API Node.js Wrapper
|
|
2
2
|
|
|
3
|
-
Bu proje, Türk Dil Kurumu (TDK) sözlük verilerine Node.js ortamından doğrudan, hızlı ve güvenilir bir şekilde erişim sağlamak amacıyla geliştirilmiş, TypeScript tabanlı resmî olmayan bir sarmalayıcı (wrapper) kütüphanedir. Herhangi bir dış bağımlılığa veya ikili (binary) dosyaya ihtiyaç duymadan HTTP üzerinden güncel verileri çeker.
|
|
3
|
+
Bu proje, Türk Dil Kurumu (TDK) sözlük verilerine Node.js ortamından doğrudan, hızlı ve güvenilir bir şekilde erişim sağlamak amacıyla geliştirilmiş, TypeScript tabanlı resmî olmayan bir sarmalayıcı (wrapper) kütüphanedir. Herhangi bir dış bağımlılığa veya ikili (binary) dosyaya ihtiyaç duymadan HTTP üzerinden güncel verileri çeker. Kütüphanenin yanı sıra bir terminal CLI'si (`tdk`) ve dahili bir **Model Context Protocol (MCP)** sunucusu da paketle birlikte gelir.
|
|
4
4
|
|
|
5
5
|
## Kurulum
|
|
6
6
|
|
|
@@ -46,6 +46,7 @@ tdk repl
|
|
|
46
46
|
tdk kubbealti merhaba
|
|
47
47
|
tdk nisanyan merhaba
|
|
48
48
|
tdk viki merhaba
|
|
49
|
+
tdk mcp # MCP (Model Context Protocol) stdio sunucusunu başlatır
|
|
49
50
|
```
|
|
50
51
|
|
|
51
52
|
Herhangi bir komuta `--json` bayrağı eklendiğinde çıktı, insan-okunur metin yerine tek satırlık JSON olarak basılır (script/otomasyon kullanımı için):
|
|
@@ -138,6 +139,25 @@ TDK dışındaki bu üç kaynak da her zaman kullanılabilir/dokümante edilmiş
|
|
|
138
139
|
- **`TDK.getNisanyan(word)`**: Nişanyan Sözlük'ten kelimenin etimoloji paragrafını düz metin olarak döner; kelime bulunamazsa `null`.
|
|
139
140
|
- **`TDK.getWiktionary(word)`**: Türkçe Vikisözlük'ten (`tr.wiktionary.org`) resmî MediaWiki API'si (`action=query&prop=extracts`) üzerinden veri çeker — bu üçü arasında scraping olmayan, resmî ve en kararlı olanı. `{ raw, sections }` döner; `sections` metni `== Köken ==`, `=== Söyleniş ===` gibi başlıklara göre bir sözlüğe ayırır. `getWiktionarySection(word, sectionName)` tek bir bölümü (örn. `"Köken"`) büyük/küçük harf duyarsız süzer. Bu wiki'de başlık büyütme kapalı (`$wgCapitalLinks=false` — "Türkiye" ile bir küçük harfli kelime ayrı sayfalardır), o yüzden `TDK.getWiktionary("türkiye")` gibi tam eşleşmeyen aramalar otomatik olarak ilk harfi (Türkçe kurallarına göre, örn. `istanbul` → `İstanbul`) büyütülmüş hâliyle tekrar denenir.
|
|
140
141
|
|
|
142
|
+
## Model Context Protocol (MCP) Sunucusu
|
|
143
|
+
|
|
144
|
+
Paket, bir MCP stdio sunucusu içerir; böylece TDK sözlük, morfoloji, yazım denetimi ve etimoloji araçlarını Claude Desktop, Cursor, Antigravity veya herhangi bir MCP istemcisine yalnızca Node.js ile bağlayabilirsiniz — Python ya da ek bir çalışma zamanı gerekmez.
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"mcpServers": {
|
|
149
|
+
"tdk": {
|
|
150
|
+
"command": "npx",
|
|
151
|
+
"args": ["-y", "tdk-api-wrapper", "mcp"]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Global kuruluysa `tdk mcp` (veya `tdk-mcp`) komutu da aynı sunucuyu başlatır. Sunucu programatik olarak dışa aktarılan `createMcpServer()` / `runMcpServer()` ile de gömülebilir.
|
|
158
|
+
|
|
159
|
+
Sunulan araçlar: `tdk_lookup`, `tdk_meanings`, `tdk_examples`, `tdk_proverbs`, `tdk_compound_words`, `tdk_part_of_speech`, `tdk_synonyms`, `tdk_antonyms`, `tdk_origin`, `tdk_nisanyan`, `tdk_kubbealti`, `tdk_wiktionary`, `tdk_spell_check`, `tdk_proofread`, `tdk_stem`, `tdk_analyze_text`, `tdk_syllables`, `tdk_vowel_harmony`, `tdk_autocomplete`, `tdk_pattern_search`, `tdk_anagram`, `tdk_rhymes`, `tdk_compare`, `tdk_audio_url`, `tdk_word_of_the_day`, `tdk_random_word`, `tdk_rules`. Her araç JSON metin döndürür; ağ/scraping hataları fırlatmak yerine `isError: true` ile `{ "error": ... }` olarak döner.
|
|
160
|
+
|
|
141
161
|
## Hata Yönetimi
|
|
142
162
|
|
|
143
163
|
Kütüphane, ayırt edilebilir hata sınıfları fırlatır (hepsi `Error`'dan türer):
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TDK
|
|
3
|
+
} from "./chunk-ZFWZXNGY.mjs";
|
|
4
|
+
|
|
5
|
+
// src/mcp.ts
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
var VERSION = "1.7.0";
|
|
10
|
+
function ok(data) {
|
|
11
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
12
|
+
}
|
|
13
|
+
function fail(message) {
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: "text", text: JSON.stringify({ error: message }, null, 2) }],
|
|
16
|
+
isError: true
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function guard(fn) {
|
|
20
|
+
return async (args) => {
|
|
21
|
+
try {
|
|
22
|
+
return await fn(args);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function createMcpServer() {
|
|
29
|
+
const server = new McpServer({
|
|
30
|
+
name: "TDK API Server",
|
|
31
|
+
version: VERSION
|
|
32
|
+
});
|
|
33
|
+
server.tool(
|
|
34
|
+
"tdk_lookup",
|
|
35
|
+
"Bir kelimenin TDK G\xFCncel T\xFCrk\xE7e S\xF6zl\xFCk'teki ham kayd\u0131n\u0131 (t\xFCm anlamlar, \xF6rnekler, birle\u015Fikler, k\xF6ken, atas\xF6zleri) d\xF6nd\xFCr\xFCr.",
|
|
36
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime (\xF6rn: 'kalem').") },
|
|
37
|
+
guard(async ({ word }) => {
|
|
38
|
+
const results = await TDK.getWord(word);
|
|
39
|
+
if (results.length === 0)
|
|
40
|
+
return fail(`"${word}" TDK s\xF6zl\xFC\u011F\xFCnde bulunamad\u0131.`);
|
|
41
|
+
return ok(results);
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
server.tool(
|
|
45
|
+
"tdk_meanings",
|
|
46
|
+
"Bir kelimenin sadele\u015Ftirilmi\u015F anlam listesini (madde madde tan\u0131mlar) d\xF6nd\xFCr\xFCr.",
|
|
47
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
|
|
48
|
+
guard(async ({ word }) => ok({ word, meanings: await TDK.getMeanings(word) }))
|
|
49
|
+
);
|
|
50
|
+
server.tool(
|
|
51
|
+
"tdk_examples",
|
|
52
|
+
"Bir kelimenin s\xF6zl\xFCkteki \xF6rnek c\xFCmlelerini (varsa yazar\u0131yla) d\xF6nd\xFCr\xFCr.",
|
|
53
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
|
|
54
|
+
guard(async ({ word }) => ok({ word, examples: await TDK.getExamples(word) }))
|
|
55
|
+
);
|
|
56
|
+
server.tool(
|
|
57
|
+
"tdk_proverbs",
|
|
58
|
+
"Bir kelime ile kurulan atas\xF6z\xFC ve deyimleri listeler.",
|
|
59
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime (\xF6rn: 'g\xF6z').") },
|
|
60
|
+
guard(async ({ word }) => ok({ word, proverbs: await TDK.getProverbs(word) }))
|
|
61
|
+
);
|
|
62
|
+
server.tool(
|
|
63
|
+
"tdk_compound_words",
|
|
64
|
+
"Bir kelime ile olu\u015Fturulmu\u015F birle\u015Fik kelimeleri listeler (\xF6rn: 'kalem' -> 'dolma kalem').",
|
|
65
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
|
|
66
|
+
guard(async ({ word }) => ok({ word, compounds: await TDK.getCompoundWords(word) }))
|
|
67
|
+
);
|
|
68
|
+
server.tool(
|
|
69
|
+
"tdk_part_of_speech",
|
|
70
|
+
"Bir kelimenin s\xF6zc\xFCk t\xFCrlerini (isim, s\u0131fat, zarf, fiil vb.) d\xF6nd\xFCr\xFCr.",
|
|
71
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
|
|
72
|
+
guard(async ({ word }) => ok({ word, partsOfSpeech: await TDK.getPartOfSpeech(word) }))
|
|
73
|
+
);
|
|
74
|
+
server.tool(
|
|
75
|
+
"tdk_synonyms",
|
|
76
|
+
"Bir kelimenin e\u015F anlaml\u0131lar\u0131n\u0131 (yak\u0131n anlaml\u0131 kelimeler) d\xF6nd\xFCr\xFCr.",
|
|
77
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
|
|
78
|
+
guard(async ({ word }) => ok({ word, synonyms: await TDK.getSynonyms(word) }))
|
|
79
|
+
);
|
|
80
|
+
server.tool(
|
|
81
|
+
"tdk_antonyms",
|
|
82
|
+
"Bir kelimenin z\u0131t (kar\u015F\u0131t) anlaml\u0131lar\u0131n\u0131 d\xF6nd\xFCr\xFCr.",
|
|
83
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
|
|
84
|
+
guard(async ({ word }) => ok({ word, antonyms: await TDK.getAntonyms(word) }))
|
|
85
|
+
);
|
|
86
|
+
server.tool(
|
|
87
|
+
"tdk_origin",
|
|
88
|
+
"Bir kelimenin TDK'deki k\xF6ken bilgisini ve yabanc\u0131 k\xF6kenli olup olmad\u0131\u011F\u0131n\u0131 d\xF6nd\xFCr\xFCr.",
|
|
89
|
+
{ word: z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
|
|
90
|
+
guard(async ({ word }) => {
|
|
91
|
+
const [origin, foreign] = await Promise.all([TDK.getOrigin(word), TDK.isForeignWord(word)]);
|
|
92
|
+
return ok({ word, origin, isForeign: foreign });
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
server.tool(
|
|
96
|
+
"tdk_nisanyan",
|
|
97
|
+
"Ni\u015Fanyan S\xF6zl\xFCk'ten bir kelimenin ayr\u0131nt\u0131l\u0131 etimolojisini (server-rendered meta a\xE7\u0131klamas\u0131) \xE7eker.",
|
|
98
|
+
{ word: z.string().describe("Etimolojisi aranacak kelime.") },
|
|
99
|
+
guard(async ({ word }) => {
|
|
100
|
+
const etymology = await TDK.getNisanyan(word);
|
|
101
|
+
return etymology ? ok({ word, etymology }) : fail(`Ni\u015Fanyan S\xF6zl\xFCk'te "${word}" bulunamad\u0131.`);
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
server.tool(
|
|
105
|
+
"tdk_kubbealti",
|
|
106
|
+
"Kubbealt\u0131 Lugat\u0131'ndan (ticari s\xF6zl\xFCk) bir kelimenin anlamlar\u0131n\u0131 \xE7eker.",
|
|
107
|
+
{ word: z.string().describe("Aranacak kelime.") },
|
|
108
|
+
guard(async ({ word }) => {
|
|
109
|
+
const meanings = await TDK.getKubbealtiMeanings(word);
|
|
110
|
+
if (meanings === null)
|
|
111
|
+
return fail("Kubbealt\u0131 Lugat\u0131'na ula\u015F\u0131lamad\u0131.");
|
|
112
|
+
return ok({ word, meanings });
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
server.tool(
|
|
116
|
+
"tdk_wiktionary",
|
|
117
|
+
"T\xFCrk\xE7e Wiktionary'den (tr.wiktionary.org, resmi MediaWiki API) bir maddenin b\xF6l\xFCmlere ayr\u0131lm\u0131\u015F i\xE7eri\u011Fini \xE7eker.",
|
|
118
|
+
{
|
|
119
|
+
word: z.string().describe("Aranacak madde ba\u015Fl\u0131\u011F\u0131."),
|
|
120
|
+
section: z.string().optional().describe("Sadece belirli bir b\xF6l\xFCm istenirse ba\u015Fl\u0131k ad\u0131 (\xF6rn: 'K\xF6ken', '\xC7eviriler').")
|
|
121
|
+
},
|
|
122
|
+
guard(async ({ word, section }) => {
|
|
123
|
+
if (section) {
|
|
124
|
+
const text = await TDK.getWiktionarySection(word, section);
|
|
125
|
+
return text ? ok({ word, section, text }) : fail(`Wiktionary'de "${word}" i\xE7in "${section}" b\xF6l\xFCm\xFC bulunamad\u0131.`);
|
|
126
|
+
}
|
|
127
|
+
const entry = await TDK.getWiktionary(word);
|
|
128
|
+
return entry ? ok(entry) : fail(`Wiktionary'de "${word}" bulunamad\u0131.`);
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
server.tool(
|
|
132
|
+
"tdk_spell_check",
|
|
133
|
+
"Bir kelimenin do\u011Fru yaz\u0131l\u0131p yaz\u0131lmad\u0131\u011F\u0131n\u0131 denetler; yanl\u0131\u015Fsa klavye/diakritik fark\u0131ndal\u0131kl\u0131 en yak\u0131n madde \xF6nerisi verir, \xE7ekimli bi\xE7imse k\xF6k\xFCn\xFC d\xF6nd\xFCr\xFCr.",
|
|
134
|
+
{ word: z.string().describe("Yaz\u0131m\u0131 denetlenecek kelime (\xF6rn: 'yanl\u0131z', 'arabs').") },
|
|
135
|
+
guard(async ({ word }) => ok(await TDK.checkSpelling(word)))
|
|
136
|
+
);
|
|
137
|
+
server.tool(
|
|
138
|
+
"tdk_proofread",
|
|
139
|
+
"Bir T\xFCrk\xE7e metni imla, ayr\u0131/biti\u015Fik yaz\u0131m ve 'da/de', 'ki', 'mi' ba\u011Fla\xE7/ek hatalar\u0131 a\xE7\u0131s\u0131ndan denetler.",
|
|
140
|
+
{ text: z.string().describe("Denetlenecek T\xFCrk\xE7e metin.") },
|
|
141
|
+
guard(async ({ text }) => ok(await TDK.proofread(text)))
|
|
142
|
+
);
|
|
143
|
+
server.tool(
|
|
144
|
+
"tdk_stem",
|
|
145
|
+
"Bir kelimenin morfolojik k\xF6k\xFCn\xFC (ek s\u0131y\u0131rma / stemming) bulur ve \xE7ekimli olup olmad\u0131\u011F\u0131n\u0131 belirtir (\xF6rn: 'kitab\u0131m\u0131z\u0131n' -> 'kitap').",
|
|
146
|
+
{ word: z.string().describe("K\xF6k\xFC aranacak kelime.") },
|
|
147
|
+
guard(async ({ word }) => {
|
|
148
|
+
const result = await TDK.stem(word);
|
|
149
|
+
return result ? ok(result) : fail(`"${word}" i\xE7in k\xF6k tespit edilemedi.`);
|
|
150
|
+
})
|
|
151
|
+
);
|
|
152
|
+
server.tool(
|
|
153
|
+
"tdk_analyze_text",
|
|
154
|
+
"Bir metindeki her kelime i\xE7in k\xF6k, anlam ve k\xF6ken bilgisini toplu olarak \xE7\u0131kar\u0131r.",
|
|
155
|
+
{ text: z.string().describe("Analiz edilecek T\xFCrk\xE7e metin.") },
|
|
156
|
+
guard(async ({ text }) => ok(await TDK.analyzeText(text)))
|
|
157
|
+
);
|
|
158
|
+
server.tool(
|
|
159
|
+
"tdk_syllables",
|
|
160
|
+
"Bir kelimeyi T\xFCrk\xE7e hece kurallar\u0131na g\xF6re hecelere ay\u0131r\u0131r (tamamen yerel, a\u011F iste\u011Fi yok).",
|
|
161
|
+
{ word: z.string().describe("Hecelenecek kelime.") },
|
|
162
|
+
guard(async ({ word }) => ok({ word, syllables: TDK.syllabicate(word) }))
|
|
163
|
+
);
|
|
164
|
+
server.tool(
|
|
165
|
+
"tdk_vowel_harmony",
|
|
166
|
+
"Bir kelimenin b\xFCy\xFCk \xFCnl\xFC uyumuna ve k\xFC\xE7\xFCk \xFCnl\xFC uyumuna (d\xFCzl\xFCk-yuvarlakl\u0131k) uyup uymad\u0131\u011F\u0131n\u0131 kontrol eder.",
|
|
167
|
+
{ word: z.string().describe("Kontrol edilecek kelime.") },
|
|
168
|
+
guard(
|
|
169
|
+
async ({ word }) => ok({
|
|
170
|
+
word,
|
|
171
|
+
vowelHarmony: TDK.checkVowelHarmony(word),
|
|
172
|
+
labialHarmony: TDK.checkLabialHarmony(word)
|
|
173
|
+
})
|
|
174
|
+
)
|
|
175
|
+
);
|
|
176
|
+
server.tool(
|
|
177
|
+
"tdk_autocomplete",
|
|
178
|
+
"Bir \xF6nek ile ba\u015Flayan s\xF6zl\xFCk maddelerini (autocomplete) d\xF6nd\xFCr\xFCr.",
|
|
179
|
+
{ prefix: z.string().describe("Aranacak \xF6nek (\xF6rn: 'kalem').") },
|
|
180
|
+
guard(async ({ prefix }) => ok({ prefix, suggestions: await TDK.getSuggestions(prefix) }))
|
|
181
|
+
);
|
|
182
|
+
server.tool(
|
|
183
|
+
"tdk_pattern_search",
|
|
184
|
+
"Bulmaca deseni ile e\u015Fle\u015Fen s\xF6zl\xFCk maddelerini bulur: '_' veya '?' tek harf, '*' s\u0131f\u0131r ya da daha fazla harf yerine ge\xE7er (\xF6rn: 'k_l_m').",
|
|
185
|
+
{
|
|
186
|
+
pattern: z.string().describe("Desen. '_'/'?' = tek harf, '*' = s\u0131f\u0131r ya da daha fazla harf."),
|
|
187
|
+
max_results: z.number().int().min(1).max(500).default(50).describe("En fazla sonu\xE7 say\u0131s\u0131.")
|
|
188
|
+
},
|
|
189
|
+
guard(async ({ pattern, max_results }) => {
|
|
190
|
+
const matches = await TDK.patternSearch(pattern, { maxResults: max_results });
|
|
191
|
+
return ok({ pattern, count: matches.length, matches });
|
|
192
|
+
})
|
|
193
|
+
);
|
|
194
|
+
server.tool(
|
|
195
|
+
"tdk_anagram",
|
|
196
|
+
"Verilen harflerle kurulabilecek T\xFCrk\xE7e s\xF6zl\xFCk maddelerini bulur. Birebir anagram varsa onlar, yoksa harflerin bir alt k\xFCmesiyle kurulan kelimeler d\xF6ner.",
|
|
197
|
+
{
|
|
198
|
+
letters: z.string().describe("Kullan\u0131lacak harfler (\xF6rn: 'kalem')."),
|
|
199
|
+
exact_length: z.boolean().default(false).describe("Sadece harflerin tamam\u0131n\u0131 kullanan birebir anagramlar\u0131 d\xF6nd\xFCr."),
|
|
200
|
+
max_results: z.number().int().min(1).max(500).default(50).describe("En fazla sonu\xE7 say\u0131s\u0131.")
|
|
201
|
+
},
|
|
202
|
+
guard(async ({ letters, exact_length, max_results }) => {
|
|
203
|
+
const words = await TDK.findAnagrams(letters, { exactLength: exact_length, maxResults: max_results });
|
|
204
|
+
return ok({ letters, count: words.length, words });
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
server.tool(
|
|
208
|
+
"tdk_rhymes",
|
|
209
|
+
"Bir kelime ile kafiyeli (son harfleri uyu\u015Fan) s\xF6zl\xFCk maddelerini bulur.",
|
|
210
|
+
{
|
|
211
|
+
word: z.string().describe("Kafiyesi aranacak kelime."),
|
|
212
|
+
min_letters: z.number().int().min(1).default(3).describe("Uyu\u015Fmas\u0131 gereken en az son harf say\u0131s\u0131."),
|
|
213
|
+
max_results: z.number().int().min(1).max(500).default(50).describe("En fazla sonu\xE7 say\u0131s\u0131.")
|
|
214
|
+
},
|
|
215
|
+
guard(async ({ word, min_letters, max_results }) => {
|
|
216
|
+
const rhymes = await TDK.findRhymes(word, { minLetters: min_letters, maxResults: max_results });
|
|
217
|
+
return ok({ word, count: rhymes.length, rhymes });
|
|
218
|
+
})
|
|
219
|
+
);
|
|
220
|
+
server.tool(
|
|
221
|
+
"tdk_compare",
|
|
222
|
+
"\u0130ki kelimeyi anlam say\u0131s\u0131, k\xF6ken, hece b\xF6l\xFCn\xFC\u015F\xFC ve \xFCnl\xFC uyumu a\xE7\u0131s\u0131ndan kar\u015F\u0131la\u015Ft\u0131r\u0131r.",
|
|
223
|
+
{
|
|
224
|
+
a: z.string().describe("Birinci kelime."),
|
|
225
|
+
b: z.string().describe("\u0130kinci kelime.")
|
|
226
|
+
},
|
|
227
|
+
guard(async ({ a, b }) => ok(await TDK.compareWords(a, b)))
|
|
228
|
+
);
|
|
229
|
+
server.tool(
|
|
230
|
+
"tdk_audio_url",
|
|
231
|
+
"Bir kelimenin TDK seslendirme (.wav) URL'sini d\xF6nd\xFCr\xFCr (bulunamazsa null).",
|
|
232
|
+
{ word: z.string().describe("Seslendirmesi aranacak kelime.") },
|
|
233
|
+
guard(async ({ word }) => ok({ word, audioUrl: await TDK.getAudioUrl(word) }))
|
|
234
|
+
);
|
|
235
|
+
server.tool(
|
|
236
|
+
"tdk_word_of_the_day",
|
|
237
|
+
"TDK'nin 'g\xFCn\xFCn kelimesi'ni anlamlar\u0131yla d\xF6nd\xFCr\xFCr.",
|
|
238
|
+
{},
|
|
239
|
+
guard(async () => {
|
|
240
|
+
const wotd = await TDK.getWordOfTheDay();
|
|
241
|
+
return wotd ? ok(wotd) : fail("G\xFCn\xFCn kelimesi al\u0131namad\u0131.");
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
server.tool(
|
|
245
|
+
"tdk_random_word",
|
|
246
|
+
"TDK i\xE7eri\u011Finden rastgele bir kelime ya da atas\xF6z\xFC d\xF6nd\xFCr\xFCr.",
|
|
247
|
+
{},
|
|
248
|
+
guard(async () => {
|
|
249
|
+
const pick = await TDK.getRandomWord();
|
|
250
|
+
return pick ? ok(pick) : fail("Rastgele i\xE7erik al\u0131namad\u0131.");
|
|
251
|
+
})
|
|
252
|
+
);
|
|
253
|
+
server.tool(
|
|
254
|
+
"tdk_rules",
|
|
255
|
+
"TDK Yaz\u0131m K\u0131lavuzu kurallar\u0131n\u0131 listeler; 'name' verilirse o kural\u0131n tam metnini d\xF6nd\xFCr\xFCr.",
|
|
256
|
+
{
|
|
257
|
+
name: z.string().optional().describe("\u0130stenirse tek bir kural\u0131n ad\u0131 (\xF6rn: 'Ba\u011Fla\xE7 Olan da, de'nin Yaz\u0131l\u0131\u015F\u0131').")
|
|
258
|
+
},
|
|
259
|
+
guard(async ({ name }) => {
|
|
260
|
+
if (name) {
|
|
261
|
+
const rule = await TDK.getRule(name);
|
|
262
|
+
return rule ? ok({ name, rule }) : fail(`"${name}" kural\u0131 bulunamad\u0131.`);
|
|
263
|
+
}
|
|
264
|
+
const rules = await TDK.getKurallar();
|
|
265
|
+
return ok({ count: rules.length, rules });
|
|
266
|
+
})
|
|
267
|
+
);
|
|
268
|
+
return server;
|
|
269
|
+
}
|
|
270
|
+
async function runMcpServer() {
|
|
271
|
+
const server = createMcpServer();
|
|
272
|
+
const transport = new StdioServerTransport();
|
|
273
|
+
await server.connect(transport);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export {
|
|
277
|
+
createMcpServer,
|
|
278
|
+
runMcpServer
|
|
279
|
+
};
|