frysker-mcp
A local, stdio Model Context Protocol server that exposes Frysker's Frisian language aids, the Fryske Akademy's digital writing tool, as tools an agent can call mid-task.
Frysker's language aids sit behind two undocumented backends: a GraphQL language API and an XML spell-checker. This server wraps both behind a single gateway and exposes three tools, so an agent writing Frisian can look words up, translate between Dutch and Frisian, and spell-check and correct Frisian prose.
Tools
search_word
Look up a Frisian or Dutch word. Returns candidate lemmas plus full dictionary
detail for the top matches: part of speech, article (it / de), pronunciation
and hyphenation, inflections, Dutch and English translations, synonyms, variants
and Frisian definitions.
word(string, required): the word to look up.from(string, default"fry"):"fry"for Frisian,"nl"for Dutch.max(number, default5): maximum number of detailed entries.
Fuzzy and inflected input is resolved through the API's lemma-aware search, and an exact match is prioritised above prefix matches. The full candidate list is always included.
translate
Translate text between Dutch and Frisian. Long text is chunked on sentence boundaries (paragraph breaks preserved) and translated sequentially.
text(string, required): the text to translate.from(string, default"nl"):"nl"(Dutch) or"fry"(Frisian).
English is not supported by the backend. English input is rejected with a clear message instead of being echoed back.
check_text
Spell/grammar/variant check Frisian text. Reports structured issues
(SPELLING_FRIES, HOLLANISME, FARIANT), each with the offending word, its
character offsets and ranked suggestions.
text(string, required): the Frisian text to check.level(string, default"B1"): target language level (A1toC2).fix(boolean, defaultfalse): whentrue, apply the top-ranked suggestion per issue and return the corrected text plus a change log.types(array, optional): restrict fixes to specific issue types.
fix defaults to off, so a plain call never rewrites text.
Install and run
The package is not published yet, but it runs from source:
npm install
npm run build
node dist/index.js
Set FRYSKER_MOCK=1 to run against captured fixtures with no network access:
FRYSKER_MOCK=1 node dist/index.js
Configuration
Requests time out (default ~20s) and retry once on network errors or 5xx responses. A 4xx response or a GraphQL validation error is reported immediately. Hard failures surface as MCP tool errors carrying the underlying message.
Client configuration
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"frysker": {
"command": "npx",
"args": ["-y", "frysker-mcp"]
}
}
}
opencode
Add to opencode.json (or opencode.jsonc):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"frysker": {
"type": "local",
"command": ["npx", "-y", "frysker-mcp"],
"enabled": true
}
}
}
To run from a local checkout instead, point command at the built entry point:
{
"command": ["node", "/absolute/path/to/frysker-mcp/dist/index.js"]
}
Development
npm run build # compile to dist/
npm run typecheck # typecheck sources and tests
npm test # run the test suite (Vitest, offline via MockGateway)
npm run test:watch # re-run tests on change
Tests assert external behaviour only, injected with the mock gateway, and never touch the network.
Notes
Both backends are undocumented and reverse-engineered from the site's network traffic, so they may change without notice. The env-overridable endpoints and the isolated gateway contain that risk. The checker credential is a public token embedded in Frysker's client JavaScript, not a user secret.
The published schema docs describe the v9 schema, but the public, unauthenticated
deployment (the one Frysker's own web client calls) is still v8. The v9 endpoint
requires an Authorization header, so it is reachable only by setting
FRYSKER_GRAPHQL_AUTH (and FRYSKER_GRAPHQL_URL). The server probes the schema
once and includes v9-only sense-level subforms only when the configured endpoint
supports them, so it stays valid against either version.