mcpField
O
openroles

openroles

ローカル
github.com/aranculletonビジネス・マーケティング14 日前に更新

openroles について

openrolesは、企業の採用ページから求人を探すPythonライブラリ、コマンドラインツール、MCPサーバーです。15種類のATSと対応する採用サイトの求人情報を共通形式にまとめます。

主な機能

  1. 0115種類のATSから求人を取得
  2. 02企業名、URL、採用ページから求人ボードを特定
  3. 03キーワード、勤務地、日付、リモート条件で絞り込み
  4. 04共通項目と応募リンクを返す
  5. 05Pythonライブラリとコマンドラインツールを提供

活用シーン

  1. 01指定企業の募集中の求人を探す
  2. 02職種名、勤務地、掲載時期で求人を検索
  3. 03異なるサイトにある同一求人を照合

MCP 対応

stdioのMCPサーバーとして `find_job_board` と `list_open_roles` ツールを公開し、MCPクライアントやエージェントによる求人ボードの特定と求人取得に対応します。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"aranculleton-openroles": {
"command": "uvx",
"args": [
"openroles"
]
}
}
}
起動コマンドuvx openroles

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
pypiopenroles0.4.0

ツール

2

掲載時のツール一覧 · 3 日前に更新

パラメーター型必須説明
targetstringはい会社名、採用ページの URL、または求人ボードの URL

詳細

openroles

雇用主自身の採用システムから、すべての募集職種をそのまま取得します。 15 種類の応募者追跡システム(Greenhouse、Lever、Ashby、Workday、Workable、Teamtailor、Personio、Recruitee、Rippling、JazzHR、Gem、Polymer、Manatal、Homerun、ClearCompany)に加え、求人情報を検索エンジン向けに公開しているあらゆる採用サイトに対応し、統一された形式で取得します。雇用主自身の採用ページが使用するフィードや API から読み取ります。API キーもアカウントもスクレイピングサービスも不要で、Python 標準ライブラリ以外は何も必要ありません。

CI PyPI Python License: MIT

$ pip install openroles
$ openroles figma --query data --limit 3
2026-09-23  Data Engineer Intern (2027)      San Francisco, CA • New York, NY          https://boards.greenhouse.io/figma/jobs/6178851004?gh_jid=6178851004
2026-09-21  Data Platform Engineer           San Francisco, CA • New York, NY • Unite  https://boards.greenhouse.io/figma/jobs/6201407004?gh_jid=6201407004
2026-09-21  PhD Intern, Data Science (2027)  San Francisco, CA • New York, NY          https://boards.greenhouse.io/figma/jobs/6200626004?gh_jid=6200626004

3 open role(s)

企業名、採用ページ、求人ボードの URL、または ats:token を指定してください。求人ボードを見つけて募集中の職種をすべて読み取り、雇用主がどのシステムを使っていても同じフィールドを返します。

理由

求人サイトでは募集を見逃したり、掲載が遅れたり、古い情報が再掲載されたりします。情報源となるのは雇用主自身の求人ボードです。情報が網羅的かつ最新で、実際の応募リンクも掲載されています。ほとんどの応募者追跡システムは、雇用主自身の採用ページ向けに、その求人ボードを JSON、RSS、XML として公開しています。openroles は同じ方法で丁寧に読み取り、対応可能なすべてのシステムをひとつの関数から利用できるようにします。

インストール

pip install openroles          # or: uvx openroles <company>

Python 3.9 以降が必要です。依存関係はありません。

コマンドライン

openroles linear                                   # every open role at Linear
openroles https://jobs.ashbyhq.com/linear          # the same, from the board URL
openroles lever:zoox --query "data" --since 14     # title words, posted in the last 14 days
openroles figma --location "New York"              # filter by place (--remote for remote only)
openroles https://adobe.wd5.myworkdayjobs.com/external_experienced \
          --query "data scientist" --details       # Workday, with each posting's description
openroles detect "Figma"                           # which ATS, and the board's token
openroles hosts greenhouse:figma lever:zoox         # the hosts to allow in a network policy
openroles personio:acme                            # any system, as ats:token
openroles careersite:careers.acme.example          # a careers site with no job API
openroles linear --json > roles.json               # JSON (the default when piped), or --jsonl
openroles linear --cache ~/.cache/openroles        # an unchanged board sends nothing next run

Python

import openroles

openroles.detect("Figma")
# [Board(ats='greenhouse', token='figma'), Board(ats='ashby', token='figma')]

jobs = openroles.fetch("greenhouse:figma", query="data", location="New York")
for job in jobs:
    print(job.posted, job.title, job.location, job.url)

job.to_dict()   # plain JSON-ready dict

openroles.hosts("personio:acme")
# ['acme.jobs.personio.de', 'acme.jobs.personio.com']: what a firewall must allow

openroles.job_id("https://www.acme.example/careers/?gh_jid=4012345")
# 'gh-4012345': the same id fetch() gives that posting, from its address alone

job_id は、雇用主の求人ボードで見つけた求人と求人サイトに掲載された求人を照合するために使います。Greenhouse(gh_jid を含むあらゆるページにも対応)、Lever、Ashby、Rippling、Workable、Personio、Workday の URL を読み取り、何も取得せず、そのシステム固有の求人 ID が含まれていない URL に対しては "" を返します。Workday では、解釈が曖昧になるケースがひとつあります。パスが URL エンコード済み(「M%C3%BCnchen」)で送信される求人は、未エンコード(「München」)で送信される求人と同じ URL になり、job_id は後者として読み取ります。

求人ボードを読み取れない場合(トークンが間違っている、応答がないなど)、fetch() は openroles.BoardError を送出します。また、ホストの robots.txt でアクセスが禁止されている場合は openroles.RobotsDisallowed を送出します。

独自のアプリケーションで使う

openroles はまずライブラリとして設計されています。CLI と MCP サーバーは、fetch と detect を薄くラップしたものです。これを組み込むアプリケーションでは、起動時に一度だけ アプリケーション名を指定します。

openroles.configure(
    user_agent="acme-jobs/1.0 (+https://acme.example/contact)",  # sent with every request
    robots_agents=["acme-jobs"],   # a Disallow for your agent stops a read too
    cache_dir="~/.cache/acme-jobs/openroles",   # optional: keep answers between runs
)

cache_dir を指定すると、各求人サイトの最新の応答が、そのサイトから送られた ETag または Last-Modified の日付とともに保存され、次回の実行時にそれらを使って問い合わせます。これらに対応し、変更がない求人サイトは 304 Not Modified を返し、データを送信しないため、保存済みのコピーが読み込まれます。Last-Modified の日付があり、ETag がない応答は、最後に全体を読み込んでから最大 1 日(openroles._http の MODIFIED_MAX_AGE、24 時間)この方法で問い合わせられ、その後は一度全体を読み込みます。データが変わっても日付が変わらないホストの場合、求人情報の古さは最大 1 日です。フォルダーの有無にかかわらず、同じ実行中にもこの制限が適用されます。読み込みのたびに、求人サイトへの問い合わせは行われます。この機能はデフォルトで無効です。応答が保存されるのは、GET リクエストであり、no-store と指定されておらず、内容がすべて届いたことが確認できる場合に限られます。つまり、Content-Length の全量、チャンク形式の応答の全チャンク、または gzip ストリームの終端までが届いた場合です。長さが示されず、チャンク形式でも gzip 圧縮でもない応答は、接続が閉じた時点で終了とみなされます。途中で切断されていても同じため、毎回全体を読み込みます。保存された応答は、所有者のみがアクセスできるファイルに保存され、未使用の状態で 30 日が経過すると削除されます。保存容量は約 500 MB です。各プロセスはフォルダーの容量をこの上限以下に保ちます。そのため、2 つのプロセスが同じフォルダーに同時に書き込む場合(たとえば、長時間実行されるアプリケーションとコマンドラインからの実行)、いずれかのプロセスがフォルダー全体を次に確認するまで上限を超えることがあります。フォルダーを使い始めるとき、使用中は少なくとも 1 時間に 1 回、さらに、自身が書き込んだデータだけで上限を超えたときにも確認します。

検索で決定されるすべての項目はパラメーターのままです。query、location、remote、since_days、country、および説明をリクエストする価値がある求人を判定する関数にもできる details です。report={} を指定すると、各求人サイトで発生したエラーが設定されて返ります。openroles.robots_allows(host, paths) は、openroles が自ら確認するものと同じ robots.txt の判定を、アプリケーションがほかの用途で取得するページに対して行います。

AI エージェント向け(MCP)

openroles mcp は標準入出力を使うModel Context Protocol サーバーです。Claude、Cursor などのエージェントが、各雇用主の募集中の職種を自分で検索できます。ツールは find_job_board と list_open_roles の 2 つです(応答を短く保つため、要求されない限り説明は省略されます)。

Claude Code:

claude mcp add openroles -- uvx openroles mcp

Claude Desktop、Cursor などのクライアント(設定の mcpServers):

{
  "mcpServers": {
    "openroles": { "command": "uvx", "args": ["openroles", "mcp"] }
  }
}

ライブラリまたは CLI を使う必要があるモデル向けの簡単な概要として、llms.txt もあります。

取得できるデータ

どのシステムの求人も、すべて同じフィールドを持ちます。

フィールド
id実行間で安定しています。システムのプレフィックス(gh-、lv-、ab-、wd- など)と、そのシステム独自の ID を組み合わせたものです
ats, board求人情報の取得元(例:greenhouse、figma)
title, url職種名と応募ページ
location, locations求人に記載されたすべての勤務地を、結合した形式とリスト形式で示します
workplaceremote、hybrid、onsite。求人サイトに記載がない場合は "" です
remoteTrue、False。求人サイトに記載がない場合は None です(ハイブリッドの場合も None です)
postedYYYY-MM-DD。システムに記載がある場合は、最初に公開された日付(最終編集日ではありません)。下記を参照してください
department, employment_type求人サイトに記載がある場合
compensation雇用主が給与帯を公開している場合、その内容を求人サイトの表記どおりに示します
salary_min, salary_max, salary_currency, salary_period同じ給与帯を数値、その ISO 通貨コード、hour、day、week、month、year のいずれか、または隔週などの期間の場合は "" で示します。求人サイトが数値で公開している場合に限ります(Lever、Ashby、Recruitee、Rippling、ClearCompany、採用サイト)。説明文から読み取ることはありません
deadline求人サイトに記載がある場合
descriptionHTML を除去したプレーンテキスト

対応システム

システムリクエスト数備考
Greenhouseボードごとに1説明文に対応しています。求人に掲載された各オフィスは、その求人の勤務地の1つとして数えられます
Leverボードごとに1要件一覧を含む説明文に対応しています。EU のボードは自動検出されます
Ashbyボードごとに1説明文と掲載給与に対応しています。Ashby は初回掲載日を公開していないため、posted は求人が最後に公開された日時です
Workday20件の求人ごとに1、説明文ごとに1--query はボードを検索し、タイトルが一致し続ける間は読み込みます。--country は、ボードで国が分類されているファセットを使って絞り込みます。--details は説明文を取得しますが、対象はタイトルが --query を通過した求人のみです
Workableボードごとに1説明文に対応しています。給与には対応していません。Workable のドキュメントに基づいて作成されていますが、作成時にホストがレート制限をかけていたため、実際のボードではまだ実行されていません
Teamtailor100件の求人ごとに1説明文、ハイブリッド勤務、リモート勤務に対応しています。雇用主独自のドメイン上にある採用サイトも利用できます
Personioボードごとに1雇用主が英語で記載した説明文に対応しています。.de と .com のアカウントに対応しています
Recruiteeボードごとに1説明文、給与、締切日に対応しています。2027年2月10日以降、Recruitee は各雇用主の独自トークンを要求します。その後、トークンが必要なボードとして表示されます
Ripplingボードごとに1、説明文ごとに1説明文と日付は各求人のレコードから取得され、--details または --query を指定した場合のみ取得されます。Rippling は10分間に100件のリクエストを許可しているため、ボードごとに最大80件です
JazzHRボードごとに1説明文に対応しています。日付と給与には対応していません。フィードは1日に1回再生成されます
Gemボードごとに1説明文、ハイブリッド勤務、リモート勤務に対応しています
Polymer20件の求人ごとに1、説明文ごとに1給与に対応しています。説明文の取得方法は Rippling と同じで、ボードごとに最大60件です
Manatal100件の求人ごとに1説明文に対応しています。日付には対応していません
Homerunボードごとに1説明文と給与に対応しています。各 Homerun 採用ページがリンクしているフィードから取得します
ClearCompanyボードごとに1説明文と給与に対応しています。トークンは採用ページに表示されるサイト ID です。最初のページのみを読み込み、続きがある場合は警告を表示します
任意の採用サイト(careersite)サイトマップごとに1、求人ページごとに1各求人ページに検索エンジン向けに記載された schema.org の JobPosting を読み込みます(iCIMS や Eightfold のサイトなど)。1回の呼び出しにつき最大40ページを新しい順に読み込みます

Workday の求人が「3 Locations」と表示されている場合、主な勤務地は「および他2か所」として読み込まれます。主な勤務地ではない場所を指定して --location を使うと、その場所が他の勤務地に含まれているか確認するため、求人ページが読み込まれます。Workday はボードの最初の2,000件の求人までしかページを読み込みません。それ以降については、--query で検索するよう警告が表示されます。

detect は、企業名(Workday と ClearCompany 以外のすべてのシステムで、雇用主が使う可能性の高い名称を試します)、ボード URL、またはボードへのリンクや埋め込みを含む採用ページから、ボードを検出します。採用ページ上での表記方法は問いません。Workday のボードは名前から推測できません。URL(tenant.wdN.myworkdayjobs.com または wdN.myworkdaysite.com/recruiting/tenant)を指定してください。採用サイトは推測されません。careersite:<address> の形式で指定してください。採用ページが openroles で読み取れないシステムを使っている場合は、そのシステム名を警告に表示します。

サポート対象外とその理由

対象外にする前に、いずれも確認しました。システムが上記のリストに加わるのは、オープンな求人ボードを公開し、その利用規約と robots.txt がアクセスを許可している場合です。

システム対象外の理由
SmartRecruitersrobots.txt が LinkedIn のクローラー以外のすべてに公開 API を閉じています
SuccessFactors、Dayforce、UKG、Paycom、Pinpointrobots.txt が求人ページへのアクセスを許可していないか、ボードの利用にサインインが必要です
BambooHR、Breezy利用規約で採用ページの自動読み取りが禁止されています
Cornerstone、BrassRing、Hireology、Comeetブラウザーに発行されたセッショントークンを使ってボードを読み取ります
Phenom確認したサイトでは、robots.txt の Content-Signal を通じて、コンテンツを AI の入力として使用しないよう求めています
Oracle Recruiting求人 API は内部利用向けとされており、求人ページではブラウザー上で JobPosting が生成されます
Freshteamベンダーによってサービスが終了される予定です
iCIMS、Eightfold公開求人 API はありませんが、採用サイトでは通常 JobPosting ページが公開されているため、careersite: として読み取れます
Taleo、ADP、Paylocity、JOIN、TalentLyft、ApplicantPro読み取り機能を構築するには、まだ十分な確認ができていません

礼儀を重んじた設計

  • 最初に robots.txt を読み取り、拒否は尊重し、決して回避しません。ベンダーがエンドポイントを公開 API として文書化している場合(Greenhouse、Lever、Workable、Teamtailor、Personio、Recruitee、Rippling、JazzHR、Gem、Polymer、Manatal)、明示的な Disallow があれば読み取りを停止しますが、robots.txt が読み取れない場合は停止しません。それ以外(Ashby、Workday、Homerun、ClearCompany、すべての採用サイト)では、robots.txt が読み取り可能で、アクセスを許可している必要があります。Workday では、採用サイト独自のルールも適用されます。
  • AI の入力に使用しないよう求めているサイトは読み取りません。 openroles は AI エージェントによって実行されることが多いため、robots.txt の Content-Signal: ai-input=no を尊重します。
  • リダイレクトをたどるのは、移動先のホストの robots.txt が許可している場合に限り、回数は最大 5 回です。
  • robots.txt を読み取った後は、ホストの Crawl-delay をリクエスト間で守ります(Lever は 1 秒を指定しています)。また、RFC 9309 の指示に従い、1 日後に robots.txt を再度読み取ります。
  • ホストごとに同時進行のリクエストは最大 2 件とし、すべての呼び出しにタイムアウトを設定し、通信には gzip を使用します。実行中に 2 回以上読み取る対象には条件付きリクエスト(ETag と Last-Modified)を使い、キャッシュフォルダーがある場合は実行間でも使用します。また、このプロジェクト名を明記した正直な User-Agent を使用します。
  • DTD またはエンティティを宣言する XML は解析しません。悪意のあるフィードによる展開を防ぐためです。
  • 429 または 503 を返したボードには、その実行が終わるまで再アクセスしません。文書化されたレート制限(Rippling の 10 分間に 100 リクエスト)も超えないようにします。

これは許可されていますか?

これらのシステムの多くは、まさに雇用主の募集中の職種を別の場所に表示する目的で、エンドポイントを公開していると文書化しています。各読み取り機能のソースファイルには、ベンダー自身の説明とその掲載場所が記載されています。Workday、Ashby、Homerun、ClearCompany のエンドポイントは、それぞれの採用ページが呼び出すものです。文書化されておらず、予告なく変更される可能性があるため、openroles は robots.txt が許可している場合に限り読み取ります。採用サイトは、検索エンジン向けに公開されている求人ページだけを、robots.txt が指定するペースで読み取ります。求人を探して応募するという、ボード本来の用途に沿って、人間のペースで利用してください。サイトに過剰なリクエストを送ったり、誰かのボード全体を再公開したりするためのツールではありません。

開発の経緯

openroles は、Claude が一連の作業を最初から最後まで行う求人検索プロジェクト last-job-search から、誰でも使えるように切り出した雇用主の求人ボード読み取り機能です。

コントリビューション

コントリビューションを歓迎します。特に役立つのは、別のシステム向けの読み取り機能の追加や、「サポート対象外」のリストから項目を外すための確認です。CONTRIBUTING.md には、セットアップ方法、ライブラリを小さく礼儀正しく保つためのいくつかのルール、システム追加のチェックリストが記載されています。バグ報告や機能リクエストは Issues にお寄せください。

pip install -e . pytest ruff
pytest && ruff check .        # offline: every answer comes from tests/fixtures/

Licence

MIT. See LICENSE.

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。