Skip to main content
Glama
foss42

foss42 MCP Server

Official
by foss42

foss42 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.

Related MCP server: CountryCallingCodes

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 MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Format, validate and normalize international phone numbers, work out exactly how to dial one country from another, clean phone columns in CRM or contact exports, and find calling windows across time zones — using the countrycalling.codes API and MCP server.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides complete world location data (countries, states, cities) as an MCP server for AI assistants, enabling search and retrieval of geographic information through 11 tools and 5 resources.
    182 npm
    2
    MIT