mcp
Open Source foss42 MCP Server
Install / Use
claude mcp add foss42 -- npx -y github:foss42/mcpIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
Development & EngineeringSupported Platforms
Tags
Skill content
View source on GitHubfoss42 MCP Server
An MCP server exposing the foss42 utilities — country data, text and case conversion, and human-friendly number and date formatting.
Built with FastMCP. 5 workflow-shaped tools, no API key, no network calls — everything runs locally against bundled data.
See DESIGN.md for the reasoning and measured before/after.
Quick start
Requires Python 3.10+.
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
Run over stdio (the default, for local clients such as Claude Code or Claude Desktop):
.venv/bin/python server.py
Or over streamable HTTP, for a remotely reachable server:
.venv/bin/python server.py --transport http --host 0.0.0.0 --port 8000
The MCP endpoint is then http://<host>:<port>/mcp.
| Flag | Default | Description |
| --- | --- | --- |
| --transport | stdio | stdio or http |
| --host | 127.0.0.1 | Bind address (http only) |
| --port | 8000 | Bind port (http only) |
To try the tools by hand, see TESTING.md.
Connecting a client
Claude Code
claude mcp add foss42 -- /path/to/mcp/.venv/bin/python /path/to/mcp/server.py
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"foss42": {
"command": "/path/to/mcp/.venv/bin/python",
"args": ["/path/to/mcp/server.py"]
}
}
}
Use absolute paths, and point at the venv's interpreter rather than a bare python.
All five tools are annotated readOnlyHint, idempotentHint, destructiveHint: false and
openWorldHint: false, so clients can skip confirmation prompts.
Tools
get_country_info
Look up one or more countries and return only the fields you ask for.
get_country_info(country: str | list[str], include: list[CountryField] = None)
country takes a name, alias, or ISO alpha-2/alpha-3 code. You never need to know the
code. Pass a list to look up several at once.
Resolution is forgiving: diacritics, punctuation and the definite article are normalised
(Türkiye, Turkiye, U.S.A., The Netherlands), historical and colloquial names resolve
(Burma → Myanmar, Swaziland → Eswatini, Holland → Netherlands, Great Britain → GB),
and an ambiguous input is reported rather than guessed:
"Korea" → 'Korea' matches more than one country: North Korea (KP), South Korea (KR).
Pass the one you mean, or use search_countries to compare them.
include selects fields; the default is names, codes, flag, stats.
| Field | Contents |
| --- | --- |
| names | Common name, official name, known aliases |
| codes | ISO 3166-1 alpha-2 and alpha-3 |
| flag | Flag emoji |
| phone | International dialing code, e.g. +44 |
| stats | Area, population, female population percent (World Bank) |
| region | Continent and UN subregion |
| subdivisions | States/provinces with code, name, category |
Subdivision data exists for 11 countries: AE, AU, CA, CH, CN, ES, IN, JP, KR, SG, US. The tool says so rather than making you find out by failing.
// get_country_info("UK", include=["flag", "stats", "phone"])
{
"country": "United Kingdom", "alpha2": "GB", "flag": "🇬🇧",
"intl_phone_code": "+44",
"stats": { "area": 243610.0, "population": 67326569, "population_female_percent": 50.58 }
}
search_countries
Find countries by partial name or region when you don't know the exact name.
search_countries(query: str = None, region: str = None, limit: int = 25)
Regions are the 5 continents (Africa, Americas, Asia, Europe, Oceania) plus UN
subregions such as South America, Western Europe, Southern Asia, Caribbean — 30 in
total. Returns {matches, total, shown} and a note when truncated.
transform_text
Convert text between naming conventions and other styles.
transform_text(text: str | list[str], style: TextStyle, separator: str = "-")
Pass a list to convert many strings in one call. Identifier styles normalise _, -, .,
spaces and camelCase boundaries first, so user_id, user-id, user id and userId all
give the same result, and XMLHttpRequest → xml_http_request.
Using Grass is green as input:
| Style | Result | Style | Result |
| --- | --- | --- | --- |
| lower | grass is green | constant | GRASS_IS_GREEN |
| upper | GRASS IS GREEN | camel_snake | grass_Is_Green |
| capital | Grass Is Green | pascal_snake | Grass_Is_Green |
| title | Grass Is Green | dot | grass.is.green |
| sentence | Grass is green | kebab | grass-is-green |
| swap | gRASS IS GREEN | cobol | GRASS-IS-GREEN |
| flat | grassisgreen | train | Grass-Is-Green |
| upper_flat | GRASSISGREEN | slug | grass-is-green |
| pascal | GrassIsGreen | camel | grassIsGreen |
| snake | grass_is_green | | |
Reverse styles turn an identifier into words: camel_to_words, snake_to_words,
kebab_to_words. Also phone_to_numeric (1-800-FLOWERS → 1-800-3569377) and the
novelty styles leet, upside_down, mirror.
humanize_number
humanize_number(value: int | list[int], style: "bytes" | "social" | "rank", ...)
| Style | Example |
| --- | --- |
| bytes | 24117248 → 23 MB (spell_out=true → 23 megabytes) |
| social | 24117248 → 24.1M (system = NA/UK/SS) |
| rank | 3 → 3rd, 11 → 11th, 61 → 61st |
digits and add_space default per style, so the common case needs only value and style.
Pass a list to format a whole column in one call.
humanize_time
humanize_time(dt: str, dt_ref: str = None, fmt: str = None, units: "FULL" | "SHORT" = "FULL", ...)
2020-12-27T18:31:29 → 5 years ago (with add_adverb=true).
Errors
Tools raise ToolError, so failures reach the client as readable, actionable messages:
// get_country_info(country="Germny")
{
"content": [{ "type": "text", "text":
"No country matches 'Germny'. Closest matches: Germany (DE), Guernsey (GG). Pass one of those, or use search_countries to browse." }],
"isError": true
}
Invalid input is caught in two places: pydantic rejects anything violating the input schema
(a negative value, an unknown style) before the tool body runs, and src/errors.py
translates foss42's exceptions into messages that name the fix.
Development
.venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest
Tests drive the server in-process via fastmcp.Client(mcp) — no subprocess, no network. See
TESTING.md for manual testing with the MCP Inspector, DESIGN.md
for why the tool surface looks like this, and CONTRIBUTING.md for how
to add a tool.
Layout
server.py entrypoint and transport selection
src/mcp_app.py the FastMCP instance
src/countries.py country name/alias/code resolution and data assembly
src/enums.py TextStyle, CountryField, HumanizeStyle, SystemEnum, DateUnitsEnum
src/errors.py foss42 exceptions -> ToolError
src/tools/ country, humanize, text
tests/ pytest suite using the in-memory client
Tool logic lives in foss42/foss42-core; this repo is the MCP layer over it. Data and algorithm changes belong upstream.
License
Apache 2.0 — see LICENSE.
Related Skills
Agent-Reach
80.6kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
ruflo
72.4k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
headroom
72.0kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
CowAgent
47.0kOpen-source super AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install. (formerly chatgpt-on-wechat)
