Civil Exam Position Filter
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Civil Exam Position FilterImport examples/positions.xlsx and filter against my saved profile."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Civil Exam Position Filter
A local, explainable shortlist for Chinese civil-service and public-institution position tables. Import a file you downloaded, save a profile, and inspect three outcomes: parsed match, needs review, or does not match. Each result retains the original columns, sheet, row, file name, and SHA-256 fingerprint.
Python 3.11+ · SQLite · CLI · MCP stdio · offline browser interface · MIT

The official announcement and recruiting authority govern eligibility. A parsed match means the supplied profile satisfies the conditions this tool recognized in the imported table. It is not an eligibility certificate. Missing profile fields, unsupported clauses, blank education/major requirements, and unmapped source columns remain visible as review requirements. The tool never crawls recruitment websites or submits applications.
Install and quick start
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e .From the repository root, run the fictional example:
cpf --config examples/config.yaml import examples/positions.xlsx --announcement 2026-10-15 --year 2026 --json
cpf --config examples/config.yaml filter --verdict ok,maybe --json
cpf --config examples/config.yaml export --format xlsx --out data/demo/shortlist.xlsx --jsonThe first command imports 14 positions from two sheets with merged title rows and headers on row 3. Repeating the same file, mapping, year, and announcement date skips all 14. Profile A yields 7 parsed matches, 2 requiring review, and 5 nonmatches. The nine shortlisted rows appear in the Excel export. Profiles B and C have independently specified expected lists in examples/expected.json; tests assert every outcome. All offices, positions, profiles, and notes are fictional. Chinese text appears only where needed to demonstrate Chinese source requirements and catalogue terms.
cpf --config examples/config.yaml serve --port 8768Open http://127.0.0.1:8768. Upload tables, edit a JSON profile, filter by outcome/location/department level/keyword, save favorites and notes, compare up to five positions, and download Excel, CSV, Markdown, or JSON reports. The interface and all assets are English and local. No CDN, telemetry, API key, account, or runtime internet access is required. Install dependencies once before offline use.
Related MCP server: JobMatch MCP
Screening rules and uncertainty
The parser recognizes explicit Chinese education/degree levels, alternatives, full-time requirements, exact majors and catalogue categories, political status, grassroots years, fresh-graduate restrictions, gender, service-project status, explicit residence/origin names, selected certificates, CET scores, named work experience, ages, and birth-date cutoffs.
Rules are deliberately narrow. Semicolons, Chinese periods, and newlines separate independent conditions. Unconsumed qualifiers and compound prose stay uncertain; no language model guesses their meaning. For example:
Source condition | Behavior |
本科及以上 | Bachelor or higher education |
仅限硕士研究生 | Master education exactly |
冶金工程 | Exact profile major name matches |
材料类 | Hierarchy match only with a confirmed applicable catalogue |
材料类及相关专业 | Recruiter confirmation required |
35周岁及以下 | Inclusive age 35 on the supplied reference date |
35周岁以下 | Age 35 requires boundary confirmation; 34 passes and 36 fails |
1990年1月1日以后出生(含) | Explicit inclusive birth-date cutoff |
35周岁以下(1990年X月X日以后出生) | Unsupported compound text; review required |
具有特殊项目认定资格 | Unsupported qualification; review required |
A definite failed condition gives no and the first failing reason; all other conditions and uncertainty remain in checks. Without a definite failure, any uncertainty gives maybe. Only otherwise is the result ok. Empty requirements are not automatically proof that the full announcement contains no restrictions. The tool does not infer age relaxations, equivalence, graduate-year eligibility, work-history classification, or residence hierarchy.
Age uses the announcement reference date you explicitly supply, not today's date. Birthday comparisons use completed years. A missing reference date gives maybe whenever age is required. A birth-date rule can be evaluated without an announcement date. Full-time status, fresh-graduate status, and grassroots years are user assertions; the tool does not verify supporting documents.
Major catalogue
<data-dir>/majors.csv is initialized from an eight-major undergraduate subset, covering selected materials and computing majors. This is not a complete catalogue, does not cover graduate disciplines, and is not assumed to govern a particular recruitment.
The checked values were read from the Ministry of Education's 2026 undergraduate catalogue, printed pages 16 and 18. Columns are code,name,category_code,category,discipline_code,discipline,level,source. Preserve codes as strings, including leading zeros. Replace the CSV or set majors to a reviewed local file. cpf majors search "计算机" searches all its fields.
By default, category matches remain maybe. Set catalogue_confirmed: true only after confirming that this catalogue and level apply to the recruitment. The fictional config enables this explicitly for its invented tables. A master's profile cannot automatically use the undergraduate hierarchy; exact major-name matches remain possible. Conflicting names/codes and missing catalogue entries require review. The catalogue is reread when the process starts; restart a running server after replacing it.
Profiles and configuration
birth_date: '1994-06-01'
education: bachelor
degree: bachelor
graduation_year: 2017
fresh: false
major_name: 冶金工程
major_code: '080404'
political: none
grassroots_years: 5
work_experience: []
household: AreaA
origin: AreaB
gender: male
certificates: []
english: {CET4: 450}
service: false
full_time: trueSave with cpf profile set profile.yaml; inspect with cpf profile check. Omitted or null attributes are unknown. Education is junior_college, bachelor, master, or doctor; degree adds none and omits junior_college. Political status is party, probationary, league, none, or democratic. Certificate identifiers currently recognized are legal and CPA. CET4/CET6 scores must be 0–710 or null. Boolean flags must be true/false/null. Geographic names are compared exactly; AreaA is distinct from Area A and no administrative hierarchy is inferred.
Configuration is YAML. --config overrides CPF_CONFIG. Data directory precedence: --data-dir → CPF_DATA_DIR → config data_dir → ./data. Config paths resolve beside the config; CLI/environment paths resolve from the working directory.
data_dir: ./data
profile: ./profile.yaml
majors: ./majors.csv
catalogue_confirmed: false
timezone: Asia/ShanghaiBackup timestamps use Asia/Shanghai. Recruitment dates are calendar dates, without timezone conversion. SQLite stores tables, positions, cached eligibility explanations, favorites, and manually imported applicant counts. Cache hashes include profile, catalogue, applicability setting, parser version, and reference date; every screening recalculates the rules. No stale cached verdict is reused. Profiles and the catalogue are separate files and included in backups.
Import mapping and provenance
Supported inputs are XLSX, XLS, and UTF-8/BOM CSV, up to 30 MB. Header detection scans the first ten rows for a position code, position title, and at least one other mapped field. Multi-sheet workbooks are supported. Merged title rows above the header are supported; the importer does not silently fill merged body qualifications. Excel formulas are not evaluated and trigger review.
mappings/guokao.yaml lists common national-table aliases. mappings/generic.yaml is an editable example with English aliases. Supply a path using --mapping mappings/custom.yaml. Each canonical field maps to a list of exact column aliases. A real workbook with both department and employing-division columns can map ambiguously; import fails with a request for a specific mapping rather than choosing one silently. Keep other text columns unmapped if their meaning is uncertain: their content enters the review reasons.
Numerically stored codes cannot recover leading zeros already lost by the spreadsheet. Original displayed values are retained as normalized strings, not Excel formatting or formulas' cached results. Blank rows and rows without codes are skipped with warnings. Source originals are not copied; the database retains all imported column values and source fingerprints.
Applicant CSV schema: code,applicants,as_of with optional table_id. Import using cpf applicants file.csv. Counts must be nonnegative integers, dates ISO 8601. The ratio is applicant count divided by vacancies; missing counts sort last and do not become zero. The as-of date remains attached. Reimport replaces manual counts for matching positions. A duplicate position code across tables requires table_id or the exact internal position ID. No live registration data is fetched.
CLI reference
Global flags work before or after commands: --data-dir, --config, --json, --quiet, and --version. Commands are noninteractive; output is a single JSON envelope even without --json. Quiet success emits nothing. --version prints the version string.
Command | Main arguments |
|
|
| Validate/save or inspect the profile |
| List imported table IDs and source fingerprints |
|
|
|
|
|
|
| One to five unambiguous codes or internal IDs |
| Update dated manual applicant counts atomically |
|
|
| Complete primary-record JSON/CSV interchange, independent of profile filtering |
| Search the selected catalogue |
| Optional |
| Loopback host only; |
| Official SDK stdio server |
Success: {"ok":true,"data":...,"warnings":[]}. Error: {"ok":false,"error":{"code":"NOT_FOUND","message":"Position not found"}}. Exit codes: 0 success, 1 I/O/database error, 2 invalid arguments/data, 3 missing record/file. Logs use stderr; MCP stdout is protocol-only.
Exports, backup, and restore
Screening exports default to ok,maybe; explicitly select ok for parsed matches only. Reports include reasons and raw source columns. JSON reports retain every rule check. CSV has a UTF-8 BOM. Excel cells are literal strings where appropriate, preventing formula evaluation of source text. CSV preserves literal source values: import text columns as text when opening untrusted data in spreadsheet software.
export --snapshot --format json writes versioned primary tables; CSV snapshots have record_type,data columns with each record serialized as JSON. Restore with import FILE --snapshot. Identical IDs are skipped; conflicting records fail and roll back. A snapshot does not include profile, catalogue, or cached explanations. Screening report JSON/CSV is distinct from portable snapshots and is not accepted as a snapshot.
A dated backup ZIP contains a consistent SQLite backup, profile if present, catalogue, and effective configuration. Stop running writers, extract a trusted backup into an empty directory, and point --data-dir there. External config paths may need adjustment; the default file names work without them. Keep the old data directory until the restored data has been checked. Back up before replacing profiles/catalogues or updating applicant counts. There is no remote authentication or encryption; use a trusted local machine.
MCP
{"mcpServers":{"positions":{"command":"/workspace/apps/civil-exam-position-filter/.venv/bin/cpf","args":["--config","/workspace/data/cpf/config.yaml","mcp"]}}}Tools: import_positions(path, mapping="guokao", announcement=null, year=null), filter_positions(profile=null, filters=null), explain_position(code, table=null), and search_majors(keyword). Import writes the database; filtering saves derived explanation cache entries. Pass a profile object to filter without changing the saved profile. Unknown conditions remain review-required in every adapter. See AGENTS.md.
Verification and limits
python -m pip install -e '.[dev]'
ruff check .
ruff format --check .
pytest -q --cov=civil_exam_position_filter --cov-report=term-missingCI runs Ubuntu Python 3.11/3.12. Tests cover over 30 condition forms, boundary dates, three complete expected lists, XLS/XLSX/CSV imports, ambiguity, atomic rollback, backup restoration, all CLI/MCP tools, a real MCP subprocess, and Web workflows. Browser acceptance covers desktop/mobile filtering, notes, comparison, profile save, upload, and downloaded exports. Validation record.
The parser does not understand every province's prose, combined age exceptions, every certificate, administrative geography, graduate catalogues, or recruitment-specific definitions. Unknown conditions require human confirmation. Large inputs are read into memory; the 30 MB compressed-file cap is not a hostile-file sandbox. This is a trusted, single-user local application with no multi-user access controls. Optional future work: reviewed province/year mappings, more explicit rule grammars, profile version history, and catalogue-specific applicability metadata.
MIT. Changelog.
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server for China brand visibility, destination demand, and KOL discovery workflows.
China company tools via MCP; separate HTTP x402 screening reports and QCC qualifications.
Sanctions Screening MCP — screen people, companies, vessels, and aircraft
City hiring-compliance MCP server with regulation search and full audit risk scoring.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceEnables automated labor and service contract risk review through MCP, supporting single or batch contract analysis, risk knowledge base queries, and regional regulation lookups.-
- FlicenseNot gradedqualityCmaintenanceEnables AI-powered job search and resume matching with strict skill verification, resume parsing, and configurable user preferences, plus MCP tools for job search, Excel export, and email dispatch.-
- AlicenseNot gradedqualityFmaintenanceEnables reviewing grant application text, running deterministic eval cases, and executing Office of Research Aid packet workflows through MCP.Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables due diligence and KYC by querying PEPs, national and international sanctions, debarment lists, arrest warrants, criminal records, leniency agreements, and forced labor registries via hosted, prepaid read-only MCP tools.MIT