Skip to content

Commit 4af5ccc

Browse files
committed
v0.1.0: Initial release — CN→TW term conversion MCP
8 tools: convert_text, lookup_term, search_terms, list_categories, add_term, remove_term, update_dictionary, get_stats Data sources: g0v/moedict-data-csld (JSON + CSV), Wikipedia
0 parents  commit 4af5ccc

File tree

12 files changed

+1168
-0
lines changed

12 files changed

+1168
-0
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.png filter=lfs diff=lfs merge=lfs -text binary
2+
mcpb/server/* binary
3+
*.mcpb binary

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.build/
2+
.swiftpm/
3+
Package.resolved
4+
*.xcodeproj
5+
*.xcworkspace
6+
DerivedData/
7+
mcpb/server/*
8+
mcpb/*.mcpb

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Changelog
2+
3+
## [0.1.0] - 2026-02-22
4+
5+
### Added
6+
- Initial release
7+
- Text conversion: `convert_text` (longest-match-first algorithm)
8+
- Term lookup: `lookup_term`, `search_terms`
9+
- Dictionary info: `list_categories`, `get_stats`
10+
- Custom terms: `add_term`, `remove_term`
11+
- Online update: `update_dictionary` (g0v JSON/CSV + Wikipedia)
12+
- Data sources: g0v/moedict-data-csld, Wikipedia cross-strait term lists

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Che Cheng
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.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// swift-tools-version: 5.9
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "CheCn2TwMCP",
6+
platforms: [.macOS(.v13)],
7+
products: [
8+
.library(name: "CheCn2TwMCPCore", targets: ["CheCn2TwMCPCore"])
9+
],
10+
dependencies: [
11+
.package(url: "https://github.com/modelcontextprotocol/swift-sdk.git", from: "0.10.2")
12+
],
13+
targets: [
14+
.target(
15+
name: "CheCn2TwMCPCore",
16+
dependencies: [.product(name: "MCP", package: "swift-sdk")],
17+
path: "Sources/CheCn2TwMCPCore"
18+
),
19+
.executableTarget(
20+
name: "CheCn2TwMCP",
21+
dependencies: ["CheCn2TwMCPCore"],
22+
path: "Sources/CheCn2TwMCP"
23+
),
24+
.testTarget(
25+
name: "CheCn2TwMCPTests",
26+
dependencies: ["CheCn2TwMCPCore"],
27+
path: "Tests/CheCn2TwMCPTests"
28+
)
29+
]
30+
)

README.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# che-cn2tw-mcp
2+
3+
Swift native MCP Server for converting Chinese Mainland terms to Taiwanese Mandarin equivalents.
4+
5+
Detects and replaces mainland Chinese vocabulary with Taiwan-standard phrasing, powered by dictionaries from g0v (MOE data) and Wikipedia.
6+
7+
## Build
8+
9+
Requires Swift 5.9+ and macOS 13+.
10+
11+
```bash
12+
git clone https://github.com/kiki830621/che-cn2tw-mcp.git
13+
cd che-cn2tw-mcp
14+
swift build -c release
15+
```
16+
17+
Binary location: `.build/release/CheCn2TwMCP`
18+
19+
## Installation
20+
21+
### Option A: Claude Code CLI
22+
23+
```bash
24+
claude mcp add che-cn2tw-mcp -s user -- /path/to/.build/release/CheCn2TwMCP
25+
```
26+
27+
Verify:
28+
29+
```bash
30+
claude mcp get che-cn2tw-mcp
31+
# Should show: Status: ✓ Connected
32+
```
33+
34+
### Option B: Edit config directly
35+
36+
Add to `~/.claude.json`:
37+
38+
```json
39+
{
40+
"mcpServers": {
41+
"che-cn2tw-mcp": {
42+
"type": "stdio",
43+
"command": "/path/to/.build/release/CheCn2TwMCP"
44+
}
45+
}
46+
}
47+
```
48+
49+
### Option C: Claude Desktop
50+
51+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
52+
53+
```json
54+
{
55+
"mcpServers": {
56+
"che-cn2tw-mcp": {
57+
"command": "/path/to/.build/release/CheCn2TwMCP"
58+
}
59+
}
60+
}
61+
```
62+
63+
## First Run
64+
65+
After connecting, run `update_dictionary` to download term data:
66+
67+
```
68+
update_dictionary # Download from all sources
69+
update_dictionary source=g0v # g0v only
70+
update_dictionary source=wikipedia # Wikipedia only
71+
```
72+
73+
Dictionary files are stored at `~/.che-cn2tw-mcp/`.
74+
75+
## Tools (8)
76+
77+
### Text Conversion
78+
79+
| Tool | Description |
80+
|------|-------------|
81+
| `convert_text` | Detect and replace mainland terms in text, returns converted text + change list |
82+
| `lookup_term` | Look up a single term (supports both CN→TW and TW→CN) |
83+
| `search_terms` | Fuzzy search the dictionary |
84+
85+
### Dictionary Management
86+
87+
| Tool | Description |
88+
|------|-------------|
89+
| `update_dictionary` | Download/refresh dictionary from online sources (g0v, Wikipedia) |
90+
| `add_term` | Add a custom CN→TW mapping (saved to `~/.che-cn2tw-mcp/custom.json`) |
91+
| `remove_term` | Remove a custom mapping |
92+
93+
### Info
94+
95+
| Tool | Description |
96+
|------|-------------|
97+
| `list_categories` | List all term categories with counts |
98+
| `get_stats` | Show dictionary stats (entry count, sources, last update) |
99+
100+
## Data Sources
101+
102+
| Source | Format | Scale |
103+
|--------|--------|-------|
104+
| g0v/moedict-data-csld (`=同實異名.json`) | JSON | ~750 pairs |
105+
| g0v/moedict-data-csld (同實異名.csv) | CSV | ~1,000 pairs |
106+
| Wikipedia (兩岸四地用語差異, 海峽兩岸術語差異) | Wikitext | Community-maintained |
107+
| User custom (`~/.che-cn2tw-mcp/custom.json`) | JSON | Unlimited |
108+
109+
## Usage Examples
110+
111+
Once connected, ask Claude things like:
112+
113+
- "幫我把這段文字轉成台灣用語:这个视频的质量很高"
114+
- "查一下「軟件」的台灣說法"
115+
- "搜尋跟「網路」有關的對照詞彙"
116+
- "新增自訂對照:信息 → 資訊"
117+
- "更新詞庫"
118+
- "顯示詞庫統計"
119+
120+
## Architecture
121+
122+
```
123+
Sources/
124+
├── CheCn2TwMCP/
125+
│ └── main.swift # Entry point
126+
└── CheCn2TwMCPCore/
127+
├── Server.swift # MCP Server (8 tools + dispatch)
128+
├── TermDictionary.swift # Dictionary load/save/search/convert
129+
└── DictionaryUpdater.swift # Online fetcher (g0v + Wikipedia)
130+
```
131+
132+
- **No third-party dependencies** beyond MCP Swift SDK
133+
- Uses `URLSession` for all HTTP requests
134+
- Longest-match-first algorithm prevents substring false positives
135+
- Custom terms override built-in dictionary entries
136+
137+
## How It Works
138+
139+
The `convert_text` tool uses a **longest-match-first** algorithm:
140+
141+
1. Sort all CN terms by length (descending)
142+
2. Scan through input text, matching the longest term first
143+
3. Track replaced positions to avoid overlapping replacements
144+
4. Return converted text + a change list with positions
145+
146+
```
147+
Input: "這個視頻的質量很高"
148+
Output: "這個影片的品質很高"
149+
Changes: [
150+
{ "視頻" → "影片", position: 3 },
151+
{ "質量" → "品質", position: 6 }
152+
]
153+
```
154+
155+
## License
156+
157+
MIT

Sources/CheCn2TwMCP/main.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Foundation
2+
import CheCn2TwMCPCore
3+
4+
do {
5+
let server = try await CheCn2TwMCPServer()
6+
try await server.run()
7+
} catch {
8+
fputs("Error: \(error)\n", stderr)
9+
exit(1)
10+
}

0 commit comments

Comments
 (0)