Yowes MCP Server

by hirotomasato• 225•• Scanned•Claim this listing•Request removal
Productivity & Workflowagentdocument generatormcpmodel context protocolpillow

Generate realistic teacher documents (ID cards, licenses, letters) for 13 countries via MCP.

Yowes is an open-source mcp server by hirotomasato, written mainly in Python, with 225 GitHub stars and the MIT license. Its code was last updated Sep 19, 2026.

<div align="center">

Yowes — Canva Education Document Generator

Headless MCP server that generates teacher verification documents — employment letters, teacher ID cards, teaching licenses, payslips, and more — across 13 countries.

License: MIT Python MCP Platform

Portable, self-contained, and installable anywhere.

</div>

Table of Contents


Sample outputs

Documents are rendered as high-resolution PNGs. Examples generated by this tool:

Teacher ID (US)Employment letter (US)
US teacher IDUS letter
Teacher ID (UK)Employment letter (UK)
UK teacher IDUK letter

Features

  • Headless MCP server — document generation exposed as agent-callable tools over stdio.
  • 13 countries, each with its own document types and local conventions.
  • Real school databases with street addresses, districts, and contact info.
  • Consistent profile photos per person — hash-based selection from a bundled, gender-aware photo pool.
  • Cross-platform fonts — DejaVu Sans bundled; no system-font dependency.
  • Packaged & portable — ships as a self-contained wheel (code + photos + fonts) installable with one command.

Supported countries

CodeCountryDocument types
ukUnited Kingdomemployment_letter, teacher_id, teaching_license
usUnited Statesemployment_letter, teacher_id, teaching_license
franceFranceinstallation_statement, iprof_screenshot, bylaws_extract, teaching_certificate
netherlandsNetherlandsemployment_contract, teacher_registration, duo_declaration, school_id
indonesiaIndonesiapayslip, teaching_experience_letter, nuptk_card, appointment_letter
australiaAustraliasigned_school_letter, school_id, teaching_license
canadaCanadaoct_card, teaching_license, signed_school_letter
spainSpainteaching_id, signed_school_letter, employment_contract
argentinaArgentinapayslip, employment_certificate, signed_school_letter
slovakiaSlovakiapayslip, employment_letter, signed_school_letter
mexicoMexicoteaching_id, signed_school_letter, employment_certificate
philippinesPhilippinesteaching_id, employment_certificate, teaching_license
thailandThailandpayslip, letter_of_employment

Requirements

  • Python 3.10+
  • Dependencies (installed automatically): Pillow, mcp

Installation

From the built wheel

pip install dist/yowes_doc_generator-0.1.0-py3-none-any.whl

From source (editable)

pip install -e .

Via uv

uvx --from . yowes-mcp

Usage — MCP server

The server speaks MCP over stdio — the transport used by most agent runtimes (Hermes, Claude Desktop, and any MCP client). Connect it, discover the tools, then call them.

Step 1 — Install & verify

# from the built wheel
pip install dist/yowes_doc_generator-0.1.0-py3-none-any.whl

# or editable from source
pip install -e .

Verify the install and that bundled assets resolve:

python -c "from countries.utils import load_font, get_profile_photo; \
print(load_font(30).getname()); print(get_profile_photo((280,340), person_id='x', gender='Male') is not None)"
# ('DejaVu Sans', 'Book')   <-- bundled font, not system
# True                      <-- bundled photo found

Step 2 — Run the server

# After install:
yowes-mcp

# Or from source:
python mcp_server.py

It blocks and waits for MCP requests over stdin/stdout — don't run it as a foreground terminal app expecting prompts.

Step 3 — Register in your agent runtime

Point your MCP client at the yowes-mcp command:

{
  "mcpServers": {
    "yowes": {
      "command": "yowes-mcp",
      "args": []
    }
  }
}

If yowes-mcp isn't on your PATH, use the absolute path to your interpreter and module instead:

{
  "mcpServers": {
    "yowes": {
      "command": "/path/to/python",
      "args": ["-m", "mcp_server"]
    }
  }
}

Tools

ToolDescription
list_countries_toolList available countries, display names, and their document types.
list_schools(country)List all schools for a country code.
generate_documents(...)Render one or more documents to PNG and return their paths.

list_countries_tool()

No arguments. Returns one result item per country — { code, name, document_types }. (Because a list return is split into one MCP content item per entry, iterate content to see them all.)

list_schools(country: str)

  • country (required) — country code from list_countries_tool (e.g. "us").
  • Returns one result item per school — { name, address, town, postcode, state, phone, lea }. Iterate content to see them all.

generate_documents(...)

ParameterTypeRequiredDefaultDescription
countrystring✅—Country code (e.g. "us", "uk").
first_namestring✅—Teacher's first name.
last_namestring✅—Teacher's last name.
school_namestring✅—Exact or partial school name (matched against that country's school list).
positionstring✅—Teaching position/title.
date_of_birthstring✅—DOB string, printed on the teacher ID (e.g. "12/05/1988").
genderstring—"Random""Random", "Male", or "Female" — selects the profile-photo pool.
document_typesstring[]—all typesWhich documents to render, e.g. ["employment_letter", "teacher_id"].
output_dirstring—output/Where to save PNGs (relative to the server's working dir).

Returns { country, school, document_types, files, count, output_dir } — files are absolute PNG paths.

Connect from a Python client

Minimal working client (requires pip install mcp):

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    params = StdioServerParameters(command="yowes-mcp", args=[])
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            countries = await session.call_tool("list_countries_tool", {})
            # A list return is split into one content item per entry:
            for item in countries.content:
                print(item.text)

            res = await session.call_tool("generate_documents", {
                "country": "us",
                "first_name": "John",
                "last_name": "Smith",
                "school_name": "Valley High",
                "position": "Head of Science Department",
                "date_of_birth": "12/05/1988",
                "gender": "Male",
            })
            print(res.content[0].text)

asyncio.run(main())

Typical agent workflow

  1. Call list_countries_tool to see what's available.
  2. Call list_schools("us") to pick a real school.
  3. Call generate_documents(...) with the chosen country, school, and person details.
  4. Read the returned PNG paths and use the files.

Generated PNGs are written to output/ (or the output_dir you pass).


Legacy GUI

A tkinter (CustomTkinter) GUI is still available for manual use. The core generation logic is shared.

python main_gui.py        # on Windows, use run.bat (sets TCL_LIBRARY)

The MCP server is the primary, headless interface. The GUI is optional and not required for the skill.


Project structure

yowes/
├── countries/            # Document generation core (package)
│   ├── base.py           # CountryGenerator ABC (contract)
│   ├── utils.py          # Fonts, profile photos, shared helpers
│   ├── foto/             # Bundled profile photos (package data)
│   ├── fonts/            # Bundled DejaVu fonts (package data)
│   └── <country>/        # One package per country
├── mcp_server.py         # MCP server exposing tools
├── main_gui.py           # Legacy tkinter GUI
├── docs/examples/        # Sample rendered documents
├── pyproject.toml        # Packaging, deps, entry point
├── output/               # Generated documents (git-ignored)
└── run.bat               # Windows GUI launcher

Adding a new country

  1. Create countries/<code>/__init__.py with a class inheriting countries.base.CountryGenerator.
  2. Implement the abstract methods: get_country_name, get_country_code, get_schools_data, get_first_names, get_last_names, get_positions, get_document_types, generate_document.
  3. Register it in countries/__init__.py via register_country("<code>", <Name>Generator).
  4. Optionally add a display label in main_gui.py (get_country_list / on_country_change).

The new country is automatically picked up by the MCP list_countries_tool and list_schools.


Contributors


License

MIT © 2026 hirotomasato

Yowes alternatives

View more →

Similar mcp servers in Productivity & Workflow, ranked by GitHub stars. Compare licence, recent activity and scan status before you choose.

NameStarsLicenceLast updatedScan
Yowes (this page)
hirotomasato
225MITSep 19, 2026Scanned, no flagged issues
N8n MCP
czlonkowski
23kMITOct 27, 2026Scanned, no flagged issues
Trigger Dev
triggerdotdev
17kApache-2.0Oct 31, 2026Scanned, no flagged issues
Skill Seekers
yusufkaraaslan
15kMITSep 30, 2026Scanned, no flagged issues
Windows MCP
CursorTouch
11kMITNov 1, 2026Scanned, no flagged issues
Mobile MCP
mobile-next
10kApache-2.0Oct 30, 2026Scanned, no flagged issues