tdk-api-wrapper 1.6.1 → 1.7.1

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/dist/index.js CHANGED
@@ -37,13 +37,15 @@ __export(src_exports, {
37
37
  TDKValidationError: () => TDKValidationError,
38
38
  TURKISH_SUFFIXES: () => TURKISH_SUFFIXES,
39
39
  TURKISH_VOWELS: () => TURKISH_VOWELS,
40
+ createMcpServer: () => createMcpServer,
40
41
  getStemCandidates: () => getStemCandidates,
41
42
  isVowel: () => isVowel,
42
43
  restoreConsonantSoftening: () => restoreConsonantSoftening,
43
44
  restoreGemination: () => restoreGemination,
44
45
  restoreInfinitive: () => restoreInfinitive,
45
46
  restoreVowelDrop: () => restoreVowelDrop,
46
- restoreVowelNarrowing: () => restoreVowelNarrowing
47
+ restoreVowelNarrowing: () => restoreVowelNarrowing,
48
+ runMcpServer: () => runMcpServer
47
49
  });
48
50
  module.exports = __toCommonJS(src_exports);
49
51
 
@@ -74,11 +76,7 @@ var TDKNetworkError = class extends TDKError {
74
76
  }
75
77
  };
76
78
 
77
- // src/morphology.ts
78
- var TURKISH_VOWELS = "ae\u0131io\xF6u\xFC";
79
- function isVowel(ch) {
80
- return TURKISH_VOWELS.includes(ch);
81
- }
79
+ // src/data/suffixes.ts
82
80
  var TURKISH_SUFFIXES = [
83
81
  // 9-letter composite suffixes
84
82
  "lerimizden",
@@ -481,6 +479,12 @@ var TURKISH_SUFFIXES = [
481
479
  "u",
482
480
  "\xFC"
483
481
  ];
482
+
483
+ // src/morphology.ts
484
+ var TURKISH_VOWELS = "ae\u0131io\xF6u\xFC";
485
+ function isVowel(ch) {
486
+ return TURKISH_VOWELS.includes(ch);
487
+ }
484
488
  function restoreConsonantSoftening(stem) {
485
489
  if (stem.length < 2)
486
490
  return [];
@@ -634,12 +638,7 @@ function getStemCandidates(word, minStemLength = 2, maxDepth = 4) {
634
638
  return [...new Set(candidatesWithWeight.map((c) => c.candidate))];
635
639
  }
636
640
 
637
- // src/tdk.ts
638
- var fs = __toESM(require("fs"));
639
- var path = __toESM(require("path"));
640
- var os = __toESM(require("os"));
641
- var https = __toESM(require("https"));
642
- var tls = __toESM(require("tls"));
641
+ // src/data/misspellings.ts
643
642
  var COMMON_MISSPELLINGS = {
644
643
  // -şey ile biten ve ayrı yazılması zorunlu söz öbekleri
645
644
  her\u015Fey: "her \u015Fey",
@@ -793,75 +792,10 @@ var COMMON_MISSPELLINGS = {
793
792
  babaanne: "babaanne"
794
793
  };
795
794
  var SEY_EXCEPTIONS = /* @__PURE__ */ new Set(["d\xFC\u015Fey", "e\u015Fey", "konsey", "jersey", "\u015Fey"]);
796
- var KEYBOARD_ROWS = [
797
- ["qwertyu\u0131op\u011F\xFC", 0],
798
- ["asdfghjkl\u015Fi", 0.5],
799
- ["zxcvbnm\xF6\xE7", 1]
800
- ];
801
- var KEYBOARD_COORDS = (() => {
802
- const coords = {};
803
- KEYBOARD_ROWS.forEach(([keys, offset], row) => {
804
- [...keys].forEach((key, col) => {
805
- coords[key] = [col + offset, row];
806
- });
807
- });
808
- return coords;
809
- })();
810
- var DIACRITIC_SIBLINGS = {
811
- \u0131: "i",
812
- i: "\u0131",
813
- \u00F6: "o",
814
- o: "\xF6",
815
- \u00FC: "u",
816
- u: "\xFC",
817
- \u015F: "s",
818
- s: "\u015F",
819
- \u00E7: "c",
820
- c: "\xE7",
821
- \u011F: "g",
822
- g: "\u011F",
823
- \u00E2: "a",
824
- a: "\xE2"
825
- };
826
- var KEYBOARD_ROW_SUB_COST = 0.4;
827
- var KEYBOARD_DIAGONAL_SUB_COST = 0.55;
828
- var DIACRITIC_SUB_COST = 0.3;
829
- var TRANSPOSITION_COST = 0.8;
830
- function keyboardSubCost(a, b) {
831
- if (a === b)
832
- return 0;
833
- if (DIACRITIC_SIBLINGS[a] === b)
834
- return DIACRITIC_SUB_COST;
835
- const pa = KEYBOARD_COORDS[a];
836
- const pb = KEYBOARD_COORDS[b];
837
- if (!pa || !pb)
838
- return 1;
839
- const dx = Math.abs(pa[0] - pb[0]);
840
- const dy = Math.abs(pa[1] - pb[1]);
841
- if (dy === 0 && dx <= 1 + 1e-9)
842
- return KEYBOARD_ROW_SUB_COST;
843
- if (dy === 1 && dx <= 1 + 1e-9)
844
- return KEYBOARD_DIAGONAL_SUB_COST;
845
- return 1;
846
- }
847
- var TDK = class {
848
- static BASE_URL = "https://sozluk.gov.tr";
849
- static AUDIO_API_HOST = "api.sozluk.gov.tr";
850
- static KUBBEALTI_HOST = "eski.lugatim.com";
851
- /**
852
- * `eski.lugatim.com` (Kubbealtı Lugatı's data API) sends only its leaf
853
- * certificate during the TLS handshake, omitting the intermediates a
854
- * correctly configured server would include — a server-side misconfiguration,
855
- * not something we should paper over by disabling verification. These are
856
- * the two certificates the server *should* be sending (fetched from the
857
- * leaf's own Authority Information Access URLs), supplied here so Node can
858
- * still build a full, properly verified chain up to a root it already
859
- * trusts (ISRG Root X1). If Let's Encrypt rotates this intermediate, this
860
- * stops working and every Kubbealtı call fails closed to `null` — same
861
- * fail-closed contract as the rest of this file's fragile integrations.
862
- */
863
- static KUBBEALTI_EXTRA_CA = [
864
- `-----BEGIN CERTIFICATE-----
795
+
796
+ // src/data/kubbealti-ca.ts
797
+ var KUBBEALTI_EXTRA_CA = [
798
+ `-----BEGIN CERTIFICATE-----
865
799
  MIIE2jCCAsKgAwIBAgIQTr0klH4k05SALYSlL9WzGTANBgkqhkiG9w0BAQsFADAu
866
800
  MQswCQYDVQQGEwJVUzENMAsGA1UEChMESVNSRzEQMA4GA1UEAxMHUm9vdCBZUjAe
867
801
  Fw0yNTA5MDMwMDAwMDBaFw0yODA5MDIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYw
@@ -889,7 +823,7 @@ NA3wJdl4DDUuQSV8hBgx6zoI1ZSGORprDFux7c6rhc77QZMSRrEgomBeklervEve
889
823
  86ylWmZ3WWHV6RLMi8xNvjd71r4EPIGgY7BZU/VPBkq+uA7Gb6mbJnFgV43uh3xy
890
824
  LRFgxIAphIukwTGSMZZR+AI+Qnp0BYTWovHXozOf3H8r6hozEoT02JHn0AeTfA==
891
825
  -----END CERTIFICATE-----`,
892
- `-----BEGIN CERTIFICATE-----
826
+ `-----BEGIN CERTIFICATE-----
893
827
  MIIF9DCCA9ygAwIBAgIRAPJLbRf52a18scn+p4eCaZ8wDQYJKoZIhvcNAQELBQAw
894
828
  TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
895
829
  cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjYwNTEzMDAwMDAw
@@ -923,7 +857,112 @@ RGMuHGnzS3hFIrRTfKxrzUZ9RzQWzEG3K6fJ3r2nqSltkeytis9DIBoFY9VmVyjL
923
857
  M71DMi+y1+TRSJVClEMwvA4yL++7q9XZx5r5wBRWB4kQTKH5qyoZnDw7iiuh1lID
924
858
  yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
925
859
  -----END CERTIFICATE-----`
926
- ];
860
+ ];
861
+
862
+ // src/data/keyboard-layout.ts
863
+ var KEYBOARD_ROWS = [
864
+ ["qwertyu\u0131op\u011F\xFC", 0],
865
+ ["asdfghjkl\u015Fi", 0.5],
866
+ ["zxcvbnm\xF6\xE7", 1]
867
+ ];
868
+ var KEYBOARD_COORDS = (() => {
869
+ const coords = {};
870
+ KEYBOARD_ROWS.forEach(([keys, offset], row) => {
871
+ [...keys].forEach((key, col) => {
872
+ coords[key] = [col + offset, row];
873
+ });
874
+ });
875
+ return coords;
876
+ })();
877
+ var DIACRITIC_SIBLINGS = {
878
+ \u0131: "i",
879
+ i: "\u0131",
880
+ \u00F6: "o",
881
+ o: "\xF6",
882
+ \u00FC: "u",
883
+ u: "\xFC",
884
+ \u015F: "s",
885
+ s: "\u015F",
886
+ \u00E7: "c",
887
+ c: "\xE7",
888
+ \u011F: "g",
889
+ g: "\u011F",
890
+ \u00E2: "a",
891
+ a: "\xE2"
892
+ };
893
+ var KEYBOARD_ROW_SUB_COST = 0.4;
894
+ var KEYBOARD_DIAGONAL_SUB_COST = 0.55;
895
+ var DIACRITIC_SUB_COST = 0.3;
896
+ var TRANSPOSITION_COST = 0.8;
897
+ function keyboardSubCost(a, b) {
898
+ if (a === b)
899
+ return 0;
900
+ if (DIACRITIC_SIBLINGS[a] === b)
901
+ return DIACRITIC_SUB_COST;
902
+ const pa = KEYBOARD_COORDS[a];
903
+ const pb = KEYBOARD_COORDS[b];
904
+ if (!pa || !pb)
905
+ return 1;
906
+ const dx = Math.abs(pa[0] - pb[0]);
907
+ const dy = Math.abs(pa[1] - pb[1]);
908
+ if (dy === 0 && dx <= 1 + 1e-9)
909
+ return KEYBOARD_ROW_SUB_COST;
910
+ if (dy === 1 && dx <= 1 + 1e-9)
911
+ return KEYBOARD_DIAGONAL_SUB_COST;
912
+ return 1;
913
+ }
914
+
915
+ // src/lib/edit-distance.ts
916
+ function damerauLevenshtein(a, b) {
917
+ const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
918
+ for (let i = 0; i <= a.length; i++)
919
+ dp[i][0] = i;
920
+ for (let j = 0; j <= b.length; j++)
921
+ dp[0][j] = j;
922
+ for (let i = 1; i <= a.length; i++) {
923
+ for (let j = 1; j <= b.length; j++) {
924
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
925
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
926
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
927
+ dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + cost);
928
+ }
929
+ }
930
+ }
931
+ return dp[a.length][b.length];
932
+ }
933
+ function keyboardAwareDistance(a, b) {
934
+ const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
935
+ for (let i = 0; i <= a.length; i++)
936
+ dp[i][0] = i;
937
+ for (let j = 0; j <= b.length; j++)
938
+ dp[0][j] = j;
939
+ for (let i = 1; i <= a.length; i++) {
940
+ for (let j = 1; j <= b.length; j++) {
941
+ const cost = keyboardSubCost(a[i - 1], b[j - 1]);
942
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
943
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
944
+ dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + TRANSPOSITION_COST);
945
+ }
946
+ }
947
+ }
948
+ return dp[a.length][b.length];
949
+ }
950
+
951
+ // src/lib/html.ts
952
+ function htmlToPlainText(html) {
953
+ return html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div)>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/gi, " ").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&quot;/gi, '"').replace(/&#39;|&rsquo;/gi, "'").replace(/&amp;/gi, "&").replace(/[ \t]+/g, " ").replace(/[ \t]*\n[ \t]*/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
954
+ }
955
+
956
+ // src/tdk.ts
957
+ var fs = __toESM(require("fs"));
958
+ var path = __toESM(require("path"));
959
+ var os = __toESM(require("os"));
960
+ var https = __toESM(require("https"));
961
+ var tls = __toESM(require("tls"));
962
+ var TDK = class {
963
+ static BASE_URL = "https://sozluk.gov.tr";
964
+ static AUDIO_API_HOST = "api.sozluk.gov.tr";
965
+ static KUBBEALTI_HOST = "eski.lugatim.com";
927
966
  // Configuration
928
967
  static defaultTimeoutMs = 8e3;
929
968
  static defaultRetries = 1;
@@ -1470,12 +1509,12 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1470
1509
  continue;
1471
1510
  if (Math.abs(candidate.length - cleanWord.length) > 2)
1472
1511
  continue;
1473
- const rawDist = this.damerauLevenshtein(cleanWord, candidate);
1512
+ const rawDist = damerauLevenshtein(cleanWord, candidate);
1474
1513
  if (rawDist === 0 || rawDist > 2)
1475
1514
  continue;
1476
1515
  const firstMismatch = candidate[0] === cleanWord[0] ? 0 : 1;
1477
1516
  const lengthMismatch = candidate.length === cleanWord.length ? 0 : 1;
1478
- const score = this.keyboardAwareDistance(cleanWord, candidate) + (firstMismatch > 0 ? 1.2 : 0);
1517
+ const score = keyboardAwareDistance(cleanWord, candidate) + (firstMismatch > 0 ? 1.2 : 0);
1479
1518
  const better = !best || score < best.score - 1e-9 || Math.abs(score - best.score) < 1e-9 && firstMismatch < best.firstMismatch || Math.abs(score - best.score) < 1e-9 && firstMismatch === best.firstMismatch && lengthMismatch < best.lengthMismatch;
1480
1519
  if (better) {
1481
1520
  best = { candidate, score, rawDist, firstMismatch, lengthMismatch };
@@ -1606,14 +1645,11 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1606
1645
  const contentEnd = html.indexOf("<footer", contentStart);
1607
1646
  if (contentEnd === -1)
1608
1647
  return null;
1609
- return this.htmlToPlainText(html.slice(contentStart, contentEnd));
1648
+ return htmlToPlainText(html.slice(contentStart, contentEnd));
1610
1649
  } catch {
1611
1650
  return null;
1612
1651
  }
1613
1652
  }
1614
- static htmlToPlainText(html) {
1615
- return html.replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div)>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/gi, " ").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&quot;/gi, '"').replace(/&#39;|&rsquo;/gi, "'").replace(/&amp;/gi, "&").replace(/[ \t]+/g, " ").replace(/[ \t]*\n[ \t]*/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
1616
- }
1617
1653
  /**
1618
1654
  * GETs a JSON path from Kubbealtı Lugatı's data API (`eski.lugatim.com`),
1619
1655
  * supplying `KUBBEALTI_EXTRA_CA` to work around that host's incomplete
@@ -1627,7 +1663,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1627
1663
  hostname: this.KUBBEALTI_HOST,
1628
1664
  path: path2,
1629
1665
  method: "GET",
1630
- ca: [...tls.rootCertificates, ...this.KUBBEALTI_EXTRA_CA],
1666
+ ca: [...tls.rootCertificates, ...KUBBEALTI_EXTRA_CA],
1631
1667
  headers: {
1632
1668
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
1633
1669
  }
@@ -1719,7 +1755,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1719
1755
  const entries = await this.getKubbealti(word);
1720
1756
  if (!entries)
1721
1757
  return null;
1722
- return entries.map((e) => this.htmlToPlainText(e.anlam));
1758
+ return entries.map((e) => htmlToPlainText(e.anlam));
1723
1759
  }
1724
1760
  /**
1725
1761
  * Autocomplete suggestions from Kubbealtı Lugatı's own typeahead endpoint
@@ -1755,7 +1791,7 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1755
1791
  const match = html.match(/<meta name="description" content="([^"]*)"/);
1756
1792
  if (!match)
1757
1793
  return null;
1758
- const description = this.htmlToPlainText(match[1]);
1794
+ const description = htmlToPlainText(match[1]);
1759
1795
  if (description === "\xC7a\u011Fda\u015F T\xFCrk\xE7enin Etimolojisi")
1760
1796
  return null;
1761
1797
  return description;
@@ -1986,56 +2022,6 @@ yDFx8r7i9vIJU5HS3moZLkYWAOilMaV9N56A9Bgb6dNcHkvg3NoaYA==
1986
2022
  }
1987
2023
  return analyses;
1988
2024
  }
1989
- /**
1990
- * Damerau-Levenshtein edit-distance (optimal string alignment variant):
1991
- * like classic Levenshtein but also counts an adjacent-character
1992
- * transposition (e.g. "yanlız" -> "yalnız") as a single edit instead of
1993
- * two substitutions — a very common class of typo that plain Levenshtein
1994
- * otherwise misses.
1995
- */
1996
- static damerauLevenshtein(a, b) {
1997
- const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
1998
- for (let i = 0; i <= a.length; i++)
1999
- dp[i][0] = i;
2000
- for (let j = 0; j <= b.length; j++)
2001
- dp[0][j] = j;
2002
- for (let i = 1; i <= a.length; i++) {
2003
- for (let j = 1; j <= b.length; j++) {
2004
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
2005
- dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
2006
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
2007
- dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + cost);
2008
- }
2009
- }
2010
- }
2011
- return dp[a.length][b.length];
2012
- }
2013
- /**
2014
- * Keyboard- and diacritic-aware edit distance: same optimal-string-alignment
2015
- * recurrence as {@link damerauLevenshtein}, but a substitution is charged by
2016
- * {@link keyboardSubCost} (a fraction of an edit when the two letters are
2017
- * adjacent on a Turkish Q keyboard or are ASCII/diacritic siblings) and a
2018
- * transposition costs {@link TRANSPOSITION_COST}. Insertions and deletions
2019
- * still cost a full 1. Used only to *rank* spelling candidates; the plain
2020
- * integer distance still gates whether a suggestion is offered at all.
2021
- */
2022
- static keyboardAwareDistance(a, b) {
2023
- const dp = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0));
2024
- for (let i = 0; i <= a.length; i++)
2025
- dp[i][0] = i;
2026
- for (let j = 0; j <= b.length; j++)
2027
- dp[0][j] = j;
2028
- for (let i = 1; i <= a.length; i++) {
2029
- for (let j = 1; j <= b.length; j++) {
2030
- const cost = keyboardSubCost(a[i - 1], b[j - 1]);
2031
- dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
2032
- if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
2033
- dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + TRANSPOSITION_COST);
2034
- }
2035
- }
2036
- }
2037
- return dp[a.length][b.length];
2038
- }
2039
2025
  /**
2040
2026
  * Fetches multiple words concurrently with a small delay to avoid rate limiting.
2041
2027
  */
@@ -2504,6 +2490,277 @@ var TDKClient = class {
2504
2490
  return TDK.checkLabialHarmony(word);
2505
2491
  }
2506
2492
  };
2493
+
2494
+ // src/mcp.ts
2495
+ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
2496
+ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
2497
+ var import_zod = require("zod");
2498
+ var VERSION = "1.7.0";
2499
+ function ok(data) {
2500
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
2501
+ }
2502
+ function fail(message) {
2503
+ return {
2504
+ content: [{ type: "text", text: JSON.stringify({ error: message }, null, 2) }],
2505
+ isError: true
2506
+ };
2507
+ }
2508
+ function guard(fn) {
2509
+ return async (args) => {
2510
+ try {
2511
+ return await fn(args);
2512
+ } catch (error) {
2513
+ return fail(error instanceof Error ? error.message : String(error));
2514
+ }
2515
+ };
2516
+ }
2517
+ function createMcpServer() {
2518
+ const server = new import_mcp.McpServer({
2519
+ name: "TDK API Server",
2520
+ version: VERSION
2521
+ });
2522
+ server.tool(
2523
+ "tdk_lookup",
2524
+ "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.",
2525
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime (\xF6rn: 'kalem').") },
2526
+ guard(async ({ word }) => {
2527
+ const results = await TDK.getWord(word);
2528
+ if (results.length === 0)
2529
+ return fail(`"${word}" TDK s\xF6zl\xFC\u011F\xFCnde bulunamad\u0131.`);
2530
+ return ok(results);
2531
+ })
2532
+ );
2533
+ server.tool(
2534
+ "tdk_meanings",
2535
+ "Bir kelimenin sadele\u015Ftirilmi\u015F anlam listesini (madde madde tan\u0131mlar) d\xF6nd\xFCr\xFCr.",
2536
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
2537
+ guard(async ({ word }) => ok({ word, meanings: await TDK.getMeanings(word) }))
2538
+ );
2539
+ server.tool(
2540
+ "tdk_examples",
2541
+ "Bir kelimenin s\xF6zl\xFCkteki \xF6rnek c\xFCmlelerini (varsa yazar\u0131yla) d\xF6nd\xFCr\xFCr.",
2542
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
2543
+ guard(async ({ word }) => ok({ word, examples: await TDK.getExamples(word) }))
2544
+ );
2545
+ server.tool(
2546
+ "tdk_proverbs",
2547
+ "Bir kelime ile kurulan atas\xF6z\xFC ve deyimleri listeler.",
2548
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime (\xF6rn: 'g\xF6z').") },
2549
+ guard(async ({ word }) => ok({ word, proverbs: await TDK.getProverbs(word) }))
2550
+ );
2551
+ server.tool(
2552
+ "tdk_compound_words",
2553
+ "Bir kelime ile olu\u015Fturulmu\u015F birle\u015Fik kelimeleri listeler (\xF6rn: 'kalem' -> 'dolma kalem').",
2554
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
2555
+ guard(async ({ word }) => ok({ word, compounds: await TDK.getCompoundWords(word) }))
2556
+ );
2557
+ server.tool(
2558
+ "tdk_part_of_speech",
2559
+ "Bir kelimenin s\xF6zc\xFCk t\xFCrlerini (isim, s\u0131fat, zarf, fiil vb.) d\xF6nd\xFCr\xFCr.",
2560
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
2561
+ guard(async ({ word }) => ok({ word, partsOfSpeech: await TDK.getPartOfSpeech(word) }))
2562
+ );
2563
+ server.tool(
2564
+ "tdk_synonyms",
2565
+ "Bir kelimenin e\u015F anlaml\u0131lar\u0131n\u0131 (yak\u0131n anlaml\u0131 kelimeler) d\xF6nd\xFCr\xFCr.",
2566
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
2567
+ guard(async ({ word }) => ok({ word, synonyms: await TDK.getSynonyms(word) }))
2568
+ );
2569
+ server.tool(
2570
+ "tdk_antonyms",
2571
+ "Bir kelimenin z\u0131t (kar\u015F\u0131t) anlaml\u0131lar\u0131n\u0131 d\xF6nd\xFCr\xFCr.",
2572
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
2573
+ guard(async ({ word }) => ok({ word, antonyms: await TDK.getAntonyms(word) }))
2574
+ );
2575
+ server.tool(
2576
+ "tdk_origin",
2577
+ "Bir kelimenin TDK'deki k\xF6ken bilgisini ve yabanc\u0131 k\xF6kenli olup olmad\u0131\u011F\u0131n\u0131 d\xF6nd\xFCr\xFCr.",
2578
+ { word: import_zod.z.string().describe("Aranacak T\xFCrk\xE7e kelime.") },
2579
+ guard(async ({ word }) => {
2580
+ const [origin, foreign] = await Promise.all([TDK.getOrigin(word), TDK.isForeignWord(word)]);
2581
+ return ok({ word, origin, isForeign: foreign });
2582
+ })
2583
+ );
2584
+ server.tool(
2585
+ "tdk_nisanyan",
2586
+ "Ni\u015Fanyan S\xF6zl\xFCk'ten bir kelimenin ayr\u0131nt\u0131l\u0131 etimolojisini (server-rendered meta a\xE7\u0131klamas\u0131) \xE7eker.",
2587
+ { word: import_zod.z.string().describe("Etimolojisi aranacak kelime.") },
2588
+ guard(async ({ word }) => {
2589
+ const etymology = await TDK.getNisanyan(word);
2590
+ return etymology ? ok({ word, etymology }) : fail(`Ni\u015Fanyan S\xF6zl\xFCk'te "${word}" bulunamad\u0131.`);
2591
+ })
2592
+ );
2593
+ server.tool(
2594
+ "tdk_kubbealti",
2595
+ "Kubbealt\u0131 Lugat\u0131'ndan (ticari s\xF6zl\xFCk) bir kelimenin anlamlar\u0131n\u0131 \xE7eker.",
2596
+ { word: import_zod.z.string().describe("Aranacak kelime.") },
2597
+ guard(async ({ word }) => {
2598
+ const meanings = await TDK.getKubbealtiMeanings(word);
2599
+ if (meanings === null)
2600
+ return fail("Kubbealt\u0131 Lugat\u0131'na ula\u015F\u0131lamad\u0131.");
2601
+ return ok({ word, meanings });
2602
+ })
2603
+ );
2604
+ server.tool(
2605
+ "tdk_wiktionary",
2606
+ "T\xFCrk\xE7e Wiktionary'den (tr.wiktionary.org, resmi MediaWiki API) bir maddenin b\xF6l\xFCmlere ayr\u0131lm\u0131\u015F i\xE7eri\u011Fini \xE7eker.",
2607
+ {
2608
+ word: import_zod.z.string().describe("Aranacak madde ba\u015Fl\u0131\u011F\u0131."),
2609
+ section: import_zod.z.string().optional().describe("Sadece belirli bir b\xF6l\xFCm istenirse ba\u015Fl\u0131k ad\u0131 (\xF6rn: 'K\xF6ken', '\xC7eviriler').")
2610
+ },
2611
+ guard(async ({ word, section }) => {
2612
+ if (section) {
2613
+ const text = await TDK.getWiktionarySection(word, section);
2614
+ return text ? ok({ word, section, text }) : fail(`Wiktionary'de "${word}" i\xE7in "${section}" b\xF6l\xFCm\xFC bulunamad\u0131.`);
2615
+ }
2616
+ const entry = await TDK.getWiktionary(word);
2617
+ return entry ? ok(entry) : fail(`Wiktionary'de "${word}" bulunamad\u0131.`);
2618
+ })
2619
+ );
2620
+ server.tool(
2621
+ "tdk_spell_check",
2622
+ "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.",
2623
+ { word: import_zod.z.string().describe("Yaz\u0131m\u0131 denetlenecek kelime (\xF6rn: 'yanl\u0131z', 'arabs').") },
2624
+ guard(async ({ word }) => ok(await TDK.checkSpelling(word)))
2625
+ );
2626
+ server.tool(
2627
+ "tdk_proofread",
2628
+ "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.",
2629
+ { text: import_zod.z.string().describe("Denetlenecek T\xFCrk\xE7e metin.") },
2630
+ guard(async ({ text }) => ok(await TDK.proofread(text)))
2631
+ );
2632
+ server.tool(
2633
+ "tdk_stem",
2634
+ "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').",
2635
+ { word: import_zod.z.string().describe("K\xF6k\xFC aranacak kelime.") },
2636
+ guard(async ({ word }) => {
2637
+ const result = await TDK.stem(word);
2638
+ return result ? ok(result) : fail(`"${word}" i\xE7in k\xF6k tespit edilemedi.`);
2639
+ })
2640
+ );
2641
+ server.tool(
2642
+ "tdk_analyze_text",
2643
+ "Bir metindeki her kelime i\xE7in k\xF6k, anlam ve k\xF6ken bilgisini toplu olarak \xE7\u0131kar\u0131r.",
2644
+ { text: import_zod.z.string().describe("Analiz edilecek T\xFCrk\xE7e metin.") },
2645
+ guard(async ({ text }) => ok(await TDK.analyzeText(text)))
2646
+ );
2647
+ server.tool(
2648
+ "tdk_syllables",
2649
+ "Bir kelimeyi T\xFCrk\xE7e hece kurallar\u0131na g\xF6re hecelere ay\u0131r\u0131r (tamamen yerel, a\u011F iste\u011Fi yok).",
2650
+ { word: import_zod.z.string().describe("Hecelenecek kelime.") },
2651
+ guard(async ({ word }) => ok({ word, syllables: TDK.syllabicate(word) }))
2652
+ );
2653
+ server.tool(
2654
+ "tdk_vowel_harmony",
2655
+ "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.",
2656
+ { word: import_zod.z.string().describe("Kontrol edilecek kelime.") },
2657
+ guard(
2658
+ async ({ word }) => ok({
2659
+ word,
2660
+ vowelHarmony: TDK.checkVowelHarmony(word),
2661
+ labialHarmony: TDK.checkLabialHarmony(word)
2662
+ })
2663
+ )
2664
+ );
2665
+ server.tool(
2666
+ "tdk_autocomplete",
2667
+ "Bir \xF6nek ile ba\u015Flayan s\xF6zl\xFCk maddelerini (autocomplete) d\xF6nd\xFCr\xFCr.",
2668
+ { prefix: import_zod.z.string().describe("Aranacak \xF6nek (\xF6rn: 'kalem').") },
2669
+ guard(async ({ prefix }) => ok({ prefix, suggestions: await TDK.getSuggestions(prefix) }))
2670
+ );
2671
+ server.tool(
2672
+ "tdk_pattern_search",
2673
+ "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').",
2674
+ {
2675
+ pattern: import_zod.z.string().describe("Desen. '_'/'?' = tek harf, '*' = s\u0131f\u0131r ya da daha fazla harf."),
2676
+ max_results: import_zod.z.number().int().min(1).max(500).default(50).describe("En fazla sonu\xE7 say\u0131s\u0131.")
2677
+ },
2678
+ guard(async ({ pattern, max_results }) => {
2679
+ const matches = await TDK.patternSearch(pattern, { maxResults: max_results });
2680
+ return ok({ pattern, count: matches.length, matches });
2681
+ })
2682
+ );
2683
+ server.tool(
2684
+ "tdk_anagram",
2685
+ "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.",
2686
+ {
2687
+ letters: import_zod.z.string().describe("Kullan\u0131lacak harfler (\xF6rn: 'kalem')."),
2688
+ exact_length: import_zod.z.boolean().default(false).describe("Sadece harflerin tamam\u0131n\u0131 kullanan birebir anagramlar\u0131 d\xF6nd\xFCr."),
2689
+ max_results: import_zod.z.number().int().min(1).max(500).default(50).describe("En fazla sonu\xE7 say\u0131s\u0131.")
2690
+ },
2691
+ guard(async ({ letters, exact_length, max_results }) => {
2692
+ const words = await TDK.findAnagrams(letters, { exactLength: exact_length, maxResults: max_results });
2693
+ return ok({ letters, count: words.length, words });
2694
+ })
2695
+ );
2696
+ server.tool(
2697
+ "tdk_rhymes",
2698
+ "Bir kelime ile kafiyeli (son harfleri uyu\u015Fan) s\xF6zl\xFCk maddelerini bulur.",
2699
+ {
2700
+ word: import_zod.z.string().describe("Kafiyesi aranacak kelime."),
2701
+ min_letters: import_zod.z.number().int().min(1).default(3).describe("Uyu\u015Fmas\u0131 gereken en az son harf say\u0131s\u0131."),
2702
+ max_results: import_zod.z.number().int().min(1).max(500).default(50).describe("En fazla sonu\xE7 say\u0131s\u0131.")
2703
+ },
2704
+ guard(async ({ word, min_letters, max_results }) => {
2705
+ const rhymes = await TDK.findRhymes(word, { minLetters: min_letters, maxResults: max_results });
2706
+ return ok({ word, count: rhymes.length, rhymes });
2707
+ })
2708
+ );
2709
+ server.tool(
2710
+ "tdk_compare",
2711
+ "\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.",
2712
+ {
2713
+ a: import_zod.z.string().describe("Birinci kelime."),
2714
+ b: import_zod.z.string().describe("\u0130kinci kelime.")
2715
+ },
2716
+ guard(async ({ a, b }) => ok(await TDK.compareWords(a, b)))
2717
+ );
2718
+ server.tool(
2719
+ "tdk_audio_url",
2720
+ "Bir kelimenin TDK seslendirme (.wav) URL'sini d\xF6nd\xFCr\xFCr (bulunamazsa null).",
2721
+ { word: import_zod.z.string().describe("Seslendirmesi aranacak kelime.") },
2722
+ guard(async ({ word }) => ok({ word, audioUrl: await TDK.getAudioUrl(word) }))
2723
+ );
2724
+ server.tool(
2725
+ "tdk_word_of_the_day",
2726
+ "TDK'nin 'g\xFCn\xFCn kelimesi'ni anlamlar\u0131yla d\xF6nd\xFCr\xFCr.",
2727
+ {},
2728
+ guard(async () => {
2729
+ const wotd = await TDK.getWordOfTheDay();
2730
+ return wotd ? ok(wotd) : fail("G\xFCn\xFCn kelimesi al\u0131namad\u0131.");
2731
+ })
2732
+ );
2733
+ server.tool(
2734
+ "tdk_random_word",
2735
+ "TDK i\xE7eri\u011Finden rastgele bir kelime ya da atas\xF6z\xFC d\xF6nd\xFCr\xFCr.",
2736
+ {},
2737
+ guard(async () => {
2738
+ const pick = await TDK.getRandomWord();
2739
+ return pick ? ok(pick) : fail("Rastgele i\xE7erik al\u0131namad\u0131.");
2740
+ })
2741
+ );
2742
+ server.tool(
2743
+ "tdk_rules",
2744
+ "TDK Yaz\u0131m K\u0131lavuzu kurallar\u0131n\u0131 listeler; 'name' verilirse o kural\u0131n tam metnini d\xF6nd\xFCr\xFCr.",
2745
+ {
2746
+ name: import_zod.z.string().optional().describe("\u0130stenirse tek bir kural\u0131n ad\u0131 (\xF6rn: 'Ba\u011Fla\xE7 Olan da, de'nin Yaz\u0131l\u0131\u015F\u0131').")
2747
+ },
2748
+ guard(async ({ name }) => {
2749
+ if (name) {
2750
+ const rule = await TDK.getRule(name);
2751
+ return rule ? ok({ name, rule }) : fail(`"${name}" kural\u0131 bulunamad\u0131.`);
2752
+ }
2753
+ const rules = await TDK.getKurallar();
2754
+ return ok({ count: rules.length, rules });
2755
+ })
2756
+ );
2757
+ return server;
2758
+ }
2759
+ async function runMcpServer() {
2760
+ const server = createMcpServer();
2761
+ const transport = new import_stdio.StdioServerTransport();
2762
+ await server.connect(transport);
2763
+ }
2507
2764
  // Annotate the CommonJS export names for ESM import in node:
2508
2765
  0 && (module.exports = {
2509
2766
  TDK,
@@ -2513,11 +2770,13 @@ var TDKClient = class {
2513
2770
  TDKValidationError,
2514
2771
  TURKISH_SUFFIXES,
2515
2772
  TURKISH_VOWELS,
2773
+ createMcpServer,
2516
2774
  getStemCandidates,
2517
2775
  isVowel,
2518
2776
  restoreConsonantSoftening,
2519
2777
  restoreGemination,
2520
2778
  restoreInfinitive,
2521
2779
  restoreVowelDrop,
2522
- restoreVowelNarrowing
2780
+ restoreVowelNarrowing,
2781
+ runMcpServer
2523
2782
  });
package/dist/index.mjs CHANGED
@@ -1,3 +1,7 @@
1
+ import {
2
+ createMcpServer,
3
+ runMcpServer
4
+ } from "./chunk-ZG7YRT7V.mjs";
1
5
  import {
2
6
  TDK,
3
7
  TDKClient,
@@ -13,7 +17,7 @@ import {
13
17
  restoreInfinitive,
14
18
  restoreVowelDrop,
15
19
  restoreVowelNarrowing
16
- } from "./chunk-ZFWZXNGY.mjs";
20
+ } from "./chunk-YY4WA2AO.mjs";
17
21
  export {
18
22
  TDK,
19
23
  TDKClient,
@@ -22,11 +26,13 @@ export {
22
26
  TDKValidationError,
23
27
  TURKISH_SUFFIXES,
24
28
  TURKISH_VOWELS,
29
+ createMcpServer,
25
30
  getStemCandidates,
26
31
  isVowel,
27
32
  restoreConsonantSoftening,
28
33
  restoreGemination,
29
34
  restoreInfinitive,
30
35
  restoreVowelDrop,
31
- restoreVowelNarrowing
36
+ restoreVowelNarrowing,
37
+ runMcpServer
32
38
  };