mcp

fossick as an MCP server for coding agents

The Model Context Protocol (MCP) is a standard way for an AI agent, such as Claude Code, Codex or Cursor, to discover and call tools that run outside it. This module offers fossick’s functions as MCP tools. The agent sees each tool’s name, arguments and docstring. The docstrings here are written for the agent and say when to use each option. They are the tools’ interface, and they are longer than the docstrings elsewhere in fossick.

Most tools take the arguments of the Python function they wrap, plus a limit on how much text they return, such as max_chars. A tool cuts a long result at that limit and ends it with a note that gives the number of characters cut. The note tells an agent to ask for more. Tools convert results to plain JSON types before they return them. The server uses standard input and output by default.

Search and research


source

lookup_doi

def lookup_doi(
    title:str
)->str:

Return the doi.org URL for the first Crossref match on a paper title.


source

research

def research(
    query:str, n:int=5, google:bool=False, region:str='auto', timelimit:str | None=None, sel:str | None=None,
    chars:int=4000
)->dict:

Question -> cited answer: search, read the top n readable* results in parallel (auto-escalating past bot walls, skipping bot-wall/empty pages and backfilling), return {query, sources, digest, dropped, region}. digest is cited markdown, one ## section per source, trimmed to the passages that answer the query and headed with the date the source says it was published. region is a ddgs ‘country-lang’ code, or ‘auto’ to read the country off the query — set it whenever the answer depends on jurisdiction or market. timelimit d|w|m|y keeps only recent sources.*


source

Fetching and crawling


source

crawl_site

def crawl_site(
    url:str, sel:str | None=None, follow_sel:str='a[href]', max_pages:int=10, same_domain:bool=True,
    heavy:bool=False, stealthy:bool=False, max_chars:int=4000
)->list:

Crawl from a start URL following follow_sel links (docs sites, blogs, multi-page content); returns [{url, status, markdown}] per page.


source

fetch_pages

def fetch_pages(
    urls:list, sel:str | None=None, max_chars:int=4000
)->list:

Fetch many known URLs in parallel; returns [{url, status, markdown}] in the same order as urls.


source

fetch_page

def fetch_page(
    url:str, sel:str | None=None, heavy:bool=False, stealthy:bool=False, session:bool=False, auto:bool=False,
    max_chars:int=8000
)->dict:

Fetch a URL as markdown. Always pass sel (CSS selector) to skip nav/ads. heavy=JS rendering; stealthy=anti-bot fetcher; session=reuse the logged-in debug Chrome’s cookies; auto=escalate plain->heavy->stealthy->session (winning tier in result).

Readers

One tool per source: arXiv papers, YouTube videos and searches, GitHub files and repositories, and conversion of pages and PDFs to notebooks.


source

pdf_to_notebook

def pdf_to_notebook(
    src:str, path:str | None=None, ocr:str='auto'
)->str:

Convert a PDF (URL or local path) to a notebook — one markdown cell per page. ocr: auto|on|off.


source

url_to_notebook

def url_to_notebook(
    url:str, path:str | None=None
)->str:

Convert a URL (HTML page, PDF, or arXiv paper) to a Jupyter notebook; returns the notebook path.


source

read_github_repo

def read_github_repo(
    url:str, globs:list | None=None, limit:int | None=None, max_chars_per_file:int=8000
)->dict:

Read files from a GitHub repo (URL, SSH address, or local path) filtered by glob patterns (default: README, pyproject.toml, .py). Returns {path: content}.


source

read_github_file

def read_github_file(
    url:str, max_chars:int=20000
)->str:

Read a single file from a GitHub blob URL.


source

download_youtube

def download_youtube(
    url:str, format:str='audio', save_dir:str='.'
)->str:

Download YouTube audio or video. format: audio|video|any yt-dlp format string. Returns the saved file path.


source

search_youtube

def search_youtube(
    query:str, n:int=10
)->list:

Search YouTube; returns [{title, url, channel, duration, description}].


source

read_youtube

def read_youtube(
    url:str, chars:int=20000
)->dict:

YouTube video (URL or ID) -> metadata + full English transcript (in ‘source’).


source

read_arxiv

def read_arxiv(
    url:str, include_source:bool=False, chars:int=8000, save_dir:str='.'
)->dict:

arXiv paper (ID or any arXiv URL) -> {title, authors, published, summary, pdf_path}. include_source adds the full text (30-100k chars total — raise chars only when needed).

Hidden APIs

find_hidden_apis and capture_network record the background requests a page makes and number them. The server keeps the list from the most recent of those calls, and replay_capture sends request number capture_id from it again as a plain HTTP call with the browser’s cookies. paginate_api reads every page of a JSON API, and returns at most max_items items.


source

paginate_api

def paginate_api(
    url:str, payload:dict | None=None, page_field:str='pageNumber', size_field:str='pageSize',
    results_field:str | None=None, method:str='POST', max_pages:int=10, page_start:int=1, max_items:int=500
)->list:

Paginate a JSON API, collecting all items across pages. payload is the base body (POST) or params (GET); page_field is the key incremented per page; results_field is auto-detected if None.


source

replay_capture

def replay_capture(
    capture_id:int, data:str | None=None, max_chars:int=8000
)->dict:

Re-issue a captured request (by capture_id from find_hidden_apis/capture_network) as a fast plain-HTTP call, reusing the browser’s cookies. data overrides the request body.


source

find_hidden_apis

def find_hidden_apis(
    url:str, pattern:str='*', session:bool=False, preview_chars:int=500
)->list:

Visit a page with a browser and capture the JSON/XHR API calls it makes (glob/regex pattern filters URLs). session=True captures through the logged-in debug Chrome. Each hit has a capture_id for replay_capture.

Browser and shop

browse opens a page in the debug Chrome and returns its snapshot. The server remembers that page, and the page_* tools act on it until the next browse. The shop_* tools work the same way on one shopping session, opened by shop_open; they wrap fossick.shop.


source

capture_network

def capture_network(
    url:str, pattern:str='.*', tail:int=3, port:int=9223, preview_chars:int=300
)->list:

Navigate the debug Chrome to a URL and capture outgoing network requests matching pattern (listens tail seconds after load). Each request gets a capture_id for replay_capture.


source

page_markdown

def page_markdown(
    sel:str | None=None, max_chars:int=8000
)->str:

Read the current page’s live post-JS DOM as markdown, optionally narrowed by a CSS selector.


source

page_act

def page_act(
    steps:list
)->dict:

Run a declarative flow on the current page. Steps (JSON arrays): [‘goto’,url] [‘fill’,label,value] [‘click’,label] [‘select’,label,option] [‘wait’,text] [‘wait_sel’,css] [‘read’,css] or [‘read’,css,label]. Returns {label: markdown} for every read step.


source

page_fill_form

def page_fill_form(
    fields:dict, submit:str | None=None
)->str:

Fill form fields on the current page by visible label ({label: value}; handles