> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ichabod.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Seeker tools

> Tools scoped to Seeker profiles: search, profile blobs, role interest, and Seeker-to-Seeker networking.

Calling these with an Organization key returns `forbidden`. See also the [shared tools](/tools/shared) (`get_profile`, `update_profile`, `list_matches`, `get_rate_limits`, `ping`).

## search\_roles

Search open roles with a freeform keyword query, matched across the role name, description, what-we're-looking-for blob, and Organization name. Omit `query` to browse the most recently posted roles.

<ParamField body="query" type="string">Freeform keywords. Case-insensitive substring match over the role blobs.</ParamField>
<ParamField body="limit" type="integer" default="20">1–50 per page.</ParamField>
<ParamField body="offset" type="integer" default="0">Pagination offset.</ParamField>

Returns an array of role objects with full details plus Organization info:

```json theme={null}
[
  {
    "id": "…", "name": "Horseman (headless)", "description": "…",
    "what_we_are_looking_for": "…",
    "location": "Sleepy Hollow, NY", "model": "in-person",
    "posted_at": "…", "expires_at": "…",
    "organization_id": "…", "organization_name": "The Hollow Watch", "organization_handle": "hollow-watch",
    "organization_about": "…", "organization_website": "https://hollowwatch.example"
  }
]
```

*Rate limits: search (100/hour).*

***

## get\_role

Full details of one open role.

<ParamField body="role_id" type="string (uuid)" required>From search results or a role page URL.</ParamField>

Returns the same shape as a `search_roles` item, or `not_found` if the role is closed, expired, or doesn't exist.

*Rate limits: read (200/hour).*

***

## update\_experience

Write your freeform **experience** blob — education, professional history, and skillset as prose. Replaces the whole blob. See [structuring a profile](/best-practices/profile).

<ParamField body="experience" type="string | null" required>≤6,000 chars. Shown to Organizations and on your public profile at `/s/[handle]`.</ParamField>

Returns the stored content (`profile_id`, `experience`, `what_is_next`, `updated_at`).

*Rate limits: seeker\_write (20/day, shared with `update_what_is_next`).*

***

## update\_what\_is\_next

Write your freeform **"what's next"** blob — the roles and Organizations you'd want to work with next. Replaces the whole blob.

<ParamField body="what_is_next" type="string | null" required>≤6,000 chars. Visible to every Organization and other Seekers over MCP (not just your matches); **never** on your public web page. Put compensation expectations and hard constraints here rather than in public fields — off the web, but not private from members.</ParamField>

Returns the stored content (`profile_id`, `experience`, `what_is_next`, `updated_at`).

*Rate limits: seeker\_write (20/day, shared with `update_experience`).*

***

## express\_interest\_in\_role

Express interest in an open role. **Idempotent** — re-calling returns the same record.

<ParamField body="role_id" type="string (uuid)" required>Must be an open role, else `not_found`.</ParamField>

```json theme={null}
{ "id": "…", "seeker_id": "…", "role_id": "…", "side": "Seeker", "created_at": "…" }
```

If the Organization has already expressed interest in you for this role, this call completes a [match](/concepts/interest-and-matches).

*Rate limits: express\_interest\_in\_role (30/day).*

***

## withdraw\_interest\_in\_role

Withdraw your interest in a role. If the Organization had expressed interest back, the [match](/concepts/interest-and-matches) dissolves for both of you; the Organization's interest is untouched, so re-expressing interest re-forms the match. Returns `not_found` if you had no interest in that role.

<ParamField body="role_id" type="string (uuid)" required />

```json theme={null}
{ "withdrawn": true, "role_id": "…", "match_removed": false }
```

*Rate limits: withdraw\_interest\_in\_role (30/day).*

***

## list\_interested\_organizations

Organizations that have expressed interest in you, with full role and Organization details — whether or not you've reciprocated. Only interests on currently open roles. Newest first. No inputs.

```json theme={null}
[
  {
    "interest_id": "…", "interested_at": "2026-06-09T10:00:00.000Z",
    "role_id": "…", "name": "Horseman (headless)", "description": "…",
    "what_we_are_looking_for": "…",
    "location": "Sleepy Hollow, NY", "model": "in-person",
    "posted_at": "…", "expires_at": "…",
    "organization_id": "…", "organization_name": "The Hollow Watch", "organization_handle": "hollow-watch",
    "organization_about": "…", "organization_website": "https://hollowwatch.example"
  }
]
```

Reciprocating with `express_interest_in_role` on that `role_id` creates a match.

*Rate limits: list (60/hour).*

***

## list\_role\_interests

The roles **you** have expressed interest in — your outbound pipeline — with full role and Organization details. Each entry carries a `status` of `matched` (the Organization has expressed interest back) or `pending`. Only interests on currently open roles. Newest first. No inputs.

```json theme={null}
[
  {
    "interest_id": "…", "interested_at": "2026-06-09T10:00:00.000Z",
    "status": "pending",
    "role_id": "…", "name": "Horseman (headless)", "description": "…",
    "what_we_are_looking_for": "…",
    "location": "Sleepy Hollow, NY", "model": "in-person",
    "posted_at": "…", "expires_at": "…",
    "organization_id": "…", "organization_name": "The Hollow Watch", "organization_handle": "hollow-watch",
    "organization_about": "…", "organization_website": "https://hollowwatch.example"
  }
]
```

Use this to review the roles you've already pursued.

*Rate limits: list (60/hour).*

***

# Networking (Seeker ↔ Seeker)

Connect with other Seekers. A mutual connection shares both `contact_email`s **for free** — no credits, no unlock. See [connections](/concepts/connections).

## search\_seekers

Search other Seekers with a freeform keyword query, matched across name, tagline, experience, and what's-next blobs. `contact_email` is never returned here — it's shared only on a mutual connection. Omit `query` to browse the most recently joined Seekers.

<ParamField body="query" type="string">Freeform keywords.</ParamField>
<ParamField body="limit" type="integer" default="20">1–50 per page.</ParamField>
<ParamField body="offset" type="integer" default="0">Pagination offset.</ParamField>

```json theme={null}
[
  {
    "id": "…", "handle": "crane", "name": "Ichabod Crane",
    "tagline": "Schoolmaster turned solo operator. Teaches, ships, and out-eats any room.",
    "experience": "…", "what_is_next": "…",
    "website": "https://…", "created_at": "…", "last_edited_at": "…"
  }
]
```

*Rate limits: search (100/hour).*

***

## express\_interest\_in\_seeker

Express interest in connecting with another Seeker, by `seeker_id` or `@handle`. When mutual, a connection forms and you both share contact details for free. **Idempotent**. You can't connect with yourself.

<ParamField body="seeker_id" type="string (uuid)">Provide exactly one of `seeker_id` or `handle`.</ParamField>
<ParamField body="handle" type="string">The Seeker's public `@handle`, with or without the leading `@`. Provide exactly one of `seeker_id` or `handle`.</ParamField>

```json theme={null}
{ "id": "…", "from_seeker_id": "…", "to_seeker_id": "…", "created_at": "…" }
```

*Rate limits: express\_interest\_in\_seeker (30/day).*

***

## withdraw\_interest\_in\_seeker

Withdraw your interest in connecting with another Seeker, by `seeker_id` or `@handle`. If you were already connected, the connection dissolves for both of you and you stop sharing contact details. The other Seeker's interest is untouched, so re-expressing interest reconnects you immediately. Returns `not_found` if you had no outstanding interest in that Seeker.

<ParamField body="seeker_id" type="string (uuid)">Provide exactly one of `seeker_id` or `handle`.</ParamField>
<ParamField body="handle" type="string">The Seeker's public `@handle`, with or without the leading `@`. Provide exactly one of `seeker_id` or `handle`.</ParamField>

```json theme={null}
{ "withdrawn": true, "seeker_id": "…", "connection_removed": false }
```

*Rate limits: withdraw\_interest\_in\_seeker (30/day).*

***

## list\_seekers\_interested\_in\_me

Seekers who have expressed interest in connecting with you, with their full profiles (minus `contact_email`) — whether or not mutual yet. Newest first. No inputs.

```json theme={null}
[
  {
    "interest_id": "…", "interested_at": "…",
    "seeker_id": "…", "handle": "katrina-van-tassel", "name": "Katrina Van Tassel",
    "tagline": "…", "experience": "…", "what_is_next": "…", "website": null,
    "created_at": "…", "last_edited_at": "…"
  }
]
```

*Rate limits: list (60/hour).*

***

## list\_connection\_interests

Seekers **you** have expressed interest in connecting with — your outbound side — with their full profiles (minus `contact_email`). Each entry carries a `status` of `connected` (they've expressed interest back, so you're mutually connected — use `list_connections` for their contact details) or `pending`. Newest first. No inputs.

```json theme={null}
[
  {
    "interest_id": "…", "interested_at": "…",
    "status": "pending",
    "seeker_id": "…", "handle": "katrina-van-tassel", "name": "Katrina Van Tassel",
    "tagline": "…", "experience": "…", "what_is_next": "…", "website": null,
    "created_at": "…", "last_edited_at": "…"
  }
]
```

Review this to see who you've already reached out to.

*Rate limits: list (60/hour).*

***

## list\_connections

Your mutual connections, each with the connected Seeker's `contact_email` (shared for free on connection). Newest first. No inputs.

```json theme={null}
[
  {
    "seeker_id": "…", "connected_at": "…",
    "handle": "katrina-van-tassel", "name": "Katrina Van Tassel",
    "tagline": "…", "experience": "…", "what_is_next": "…", "website": null,
    "created_at": "…", "last_edited_at": "…",
    "contact_email": "katrina-van-tassel@post.sleepyhollow.test"
  }
]
```

*Rate limits: list (60/hour).*
