FastMCP Documentation & Web Scraping Server
Enables fetching and processing GitHub repository content in markdown format, including searching through repository documentation and README files.
Provides tools for fetching web pages converted to markdown format via Jina reader, enabling content extraction and analysis from websites.
Supports indexing and searching through MDX documentation files from repositories, enabling full-text search across documentation content.
Click on "Install 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., "@FastMCP Documentation & Web Scraping Serversearch the docs for how to add tools"
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.
03-mcp
MCP-Model Context Protocol
This repository contains the homework for the MCP (Model Context Protocol) assignment.
Questions, answers, and the code used for this homework are collected below.
Question 1
Install
uvInitialize the project with
uvInstall
fastmcpFind the first
sha256inuv.lock
Answers / actions performed:
uvinstalled and verified.Project initialized with
uv init.fastmcpadded withuv add fastmcp.First
sha256inuv.lockis on line 20 forannotated-types:
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/.../annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }Related MCP server: FastMCP Documentation Search Server
Question 2 — FastMCP Transport
I updated main.py using the FastMCP starter and ran the server. The welcome screen shows the transport:
Answer: STDIO
Question 3 — Scrape Web Tool (Jina reader)
I implemented a tool using the Jina reader (https://r.jina.ai/...) and requests, added test.py to test it against https://github.com/alexeygrigorev/minsearch.
Test result (character count): 31361 → closest provided option: 29184.
Question 4 — Integrate the Tool
I added count_data.py that uses the MCP Jina-reader tool to fetch https://datatalks.club/ and count occurrences of the whole word data (case-insensitive).
Script output: 10 → closest option: 61.
Question 5 — Implement Search (minsearch)
I downloaded the FastMCP repo zip, extracted .md and .mdx files, indexed them with minsearch, and searched for demo.
First file returned for query "demo": examples/testing_demo/README.md.
Question 6 — Search Tool (ungraded)
I added a search_docs MCP tool to main.py that builds the minsearch index from the zip and returns the top filenames for a query.
Files added / modified (full contents)
main.py
from fastmcp import FastMCP
import requests
import os
import zipfile
from minsearch import Index
mcp = FastMCP("Demo 🚀")
def fetch_markdown_impl(url: str) -> str:
"""Fetch a web page using Jina reader and return its markdown text.
The Jina reader endpoint is `https://r.jina.ai/{original_url}`.
The `url` argument may be a full URL (including scheme) or a hostname/path.
"""
if not url.startswith("http://") and not url.startswith("https://"):
url = "https://" + url
target = "https://r.jina.ai/" + url
resp = requests.get(target, timeout=15)
resp.raise_for_status()
return resp.text
@mcp.tool
def fetch_markdown(url: str) -> str:
"""Return markdown content of a web page via Jina reader."""
return fetch_markdown_impl(url)
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# --- minsearch integration for documentation search ---
ZIP_URL = "https://github.com/jlowin/fastmcp/archive/refs/heads/main.zip"
ZIP_NAME = "fastmcp-main.zip"
# simple module-level cache for the built index
_INDEX_CACHE = None
def ensure_zip():
if os.path.exists(ZIP_NAME):
return
resp = requests.get(ZIP_URL, stream=True, timeout=60)
resp.raise_for_status()
with open(ZIP_NAME, "wb") as f:
for chunk in resp.iter_content(1024 * 64):
if chunk:
f.write(chunk)
def iter_md_files_from_zip(zip_path):
with zipfile.ZipFile(zip_path, "r") as z:
for name in z.namelist():
lower = name.lower()
if lower.endswith(".md") or lower.endswith(".mdx"):
data = z.read(name)
text = data.decode("utf-8", errors="replace")
if "/" in name:
_, rest = name.split("/", 1)
else:
rest = name
yield rest, text
def build_index_from_zip():
docs = []
ensure_zip()
for fname in os.listdir('.'):
if fname.lower().endswith('.zip'):
for filename, text in iter_md_files_from_zip(fname):
docs.append({'content': text, 'filename': filename})
idx = Index(text_fields=["content"], keyword_fields=["filename"])
idx.fit(docs)
return idx
def get_index():
global _INDEX_CACHE
if _INDEX_CACHE is None:
_INDEX_CACHE = build_index_from_zip()
return _INDEX_CACHE
def search_docs_impl(query: str, top_k: int = 5):
idx = get_index()
results = idx.search(query, num_results=top_k)
return results
@mcp.tool
def search_docs(query: str) -> list:
"""Search the documentation index and return top filenames for `query`."""
results = search_docs_impl(query, top_k=5)
return [r.get('filename') for r in results]
if __name__ == "__main__":
mcp.run()test.py
from main import fetch_markdown_impl
if __name__ == "__main__":
url = "https://github.com/alexeygrigorev/minsearch"
text = fetch_markdown_impl(url)
print(len(text))test_search.py
from main import search_docs_impl
if __name__ == '__main__':
res = search_docs_impl('demo', top_k=5)
if not res:
print('No results')
else:
print(res[0].get('filename'))count_data.py
from main import fetch_markdown_impl
import re
if __name__ == "__main__":
url = "https://datatalks.club/"
text = fetch_markdown_impl(url)
count = len(re.findall(r"\bdata\b", text, flags=re.IGNORECASE))
print(count)search.py
import os
import requests
import zipfile
import io
from minsearch import Index
ZIP_URL = "https://github.com/jlowin/fastmcp/archive/refs/heads/main.zip"
ZIP_NAME = "fastmcp-main.zip"
def ensure_zip():
if os.path.exists(ZIP_NAME):
print(f"Zip already exists: {ZIP_NAME}")
return
print(f"Downloading {ZIP_URL} -> {ZIP_NAME}")
resp = requests.get(ZIP_URL, stream=True, timeout=60)
resp.raise_for_status()
with open(ZIP_NAME, "wb") as f:
for chunk in resp.iter_content(1024 * 64):
if chunk:
f.write(chunk)
def iter_md_files_from_zip(zip_path):
with zipfile.ZipFile(zip_path, "r") as z:
for name in z.namelist():
lower = name.lower()
if lower.endswith(".md") or lower.endswith(".mdx"):
# read file
data = z.read(name)
text = data.decode("utf-8", errors="replace")
# strip first path segment
if "/" in name:
_, rest = name.split("/", 1)
else:
rest = name
yield rest, text
def build_index(docs):
# docs: list of {'content':..., 'filename':...}
idx = Index(text_fields=["content"], keyword_fields=["filename"])
idx.fit(docs)
return idx
def main():
ensure_zip()
docs = []
# iterate all zip files in cwd
for fname in os.listdir('.'):
if fname.lower().endswith('.zip'):
for filename, text in iter_md_files_from_zip(fname):
docs.append({'content': text, 'filename': filename})
print(f"Indexed {len(docs)} markdown files")
idx = build_index(docs)
results = idx.search("demo", num_results=5)
if not results:
print("No results")
return
# print first returned filename
first = results[0]
print(first.get('filename'))
if __name__ == '__main__':
main()Git & Repository
All changes have been committed and pushed to the current repository's
mainbranch.
Available Tools
3 toolsaddB
Add two numbers
| Name | Required | Description | Default |
|---|---|---|---|
| a | Yes | ||
| b | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. 'Add two numbers' implies a simple computation, but it doesn't disclose any behavioral traits like error handling, performance, or side effects. For a tool with no annotations, this is a significant gap in transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise and front-loaded with the core action ('Add two numbers'), using only three words with zero waste. Every sentence (though it's a single phrase) earns its place by directly stating the tool's purpose without unnecessary elaboration.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's low complexity (simple arithmetic), no annotations, and an output schema exists (which covers return values), the description is somewhat complete but lacks depth. It states what the tool does but misses behavioral and usage context, making it adequate but with clear gaps for an agent to rely on.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds minimal meaning beyond the input schema, which has 0% description coverage. It implies that parameters 'a' and 'b' are numbers to be added, but doesn't specify details like integer types or constraints. With low schema coverage, the description doesn't fully compensate, but it provides basic context, aligning with the baseline for partial compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description 'Add two numbers' clearly states the verb ('Add') and resource ('two numbers'), making the purpose immediately understandable. However, it doesn't differentiate from sibling tools (fetch_markdown, search_docs), which are unrelated to arithmetic operations, so it doesn't need sibling differentiation but could be more specific about what type of numbers or context.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention any prerequisites, limitations, or context for usage, such as when arithmetic operations are needed versus other tools. This leaves the agent without explicit usage instructions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_markdownB
Return markdown content of a web page via Jina reader.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It mentions 'Return markdown content' and 'via Jina reader', but fails to disclose critical behavioral traits such as rate limits, authentication needs, error handling, or whether it's a read-only operation. This leaves significant gaps for a tool that interacts with external web pages.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence with no wasted words, clearly front-loading the purpose. Every part ('Return markdown content', 'of a web page', 'via Jina reader') adds value, making it appropriately sized and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (fetching web content), lack of annotations, and an output schema that likely covers return values, the description is minimally complete. It states what the tool does but misses behavioral details and usage context. With an output schema, it doesn't need to explain returns, but other gaps keep it at an adequate level.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 1 parameter with 0% description coverage, so the description must compensate. It implies the 'url' parameter is for a web page, adding some meaning beyond the bare schema. However, it doesn't specify URL format constraints, validation rules, or examples, providing only basic context. This meets the baseline for low coverage but doesn't fully address the gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Return markdown content') and the resource ('of a web page'), specifying it uses 'Jina reader' as the mechanism. It distinguishes from siblings like 'add' and 'search_docs' by focusing on fetching content rather than adding or searching. However, it doesn't explicitly differentiate from potential similar tools not listed, keeping it at 4 instead of 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives like 'search_docs' for searching documents or other web-fetching tools. It lacks context on prerequisites (e.g., URL validity), exclusions, or typical use cases, leaving the agent with minimal direction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_docsB
Search the documentation index and return top filenames for query.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions the action ('Search') and return type ('top filenames'), but lacks details on permissions, rate limits, pagination, or error handling. For a search tool with zero annotation coverage, this leaves significant behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence that front-loads the core action and result. Every word earns its place, with no redundancy or unnecessary details, making it highly concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (search operation), no annotations, and an output schema present, the description is minimally adequate. It covers the basic purpose but lacks behavioral context and parameter details. The output schema likely handles return values, but the description doesn't provide enough guidance for effective use without additional context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds minimal semantics beyond the input schema. It clarifies that the 'query' parameter is used for searching, but with 0% schema description coverage and only one parameter, the baseline is 4. However, it doesn't explain query syntax, format, or examples, so it doesn't fully compensate for the lack of schema documentation, resulting in a score of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose with a specific verb ('Search') and resource ('documentation index'), and specifies what it returns ('top filenames for query'). It distinguishes itself from sibling tools like 'add' and 'fetch_markdown' by focusing on search functionality. However, it doesn't explicitly differentiate from potential similar search tools beyond the scope of this server.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention any prerequisites, exclusions, or comparisons with sibling tools like 'add' or 'fetch_markdown'. The usage context is implied (searching documentation), but no explicit guidelines are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
The three tools have clearly distinct purposes: 'add' performs arithmetic addition, 'fetch_markdown' retrieves web content, and 'search_docs' searches documentation. There is no overlap in functionality, making tool selection straightforward.
The naming is inconsistent: 'add' uses a simple verb, 'fetch_markdown' uses verb_noun with underscore, and 'search_docs' uses verb_noun with underscore but differs in style from 'fetch_markdown' (e.g., 'fetch' vs. 'search'). This mixed convention lacks a predictable pattern.
With only 3 tools, the set feels thin for a server labeled 'Documentation & Web Scraping Server'. It lacks essential scraping or documentation management operations (e.g., no update, delete, or advanced scraping tools), making the scope underdeveloped.
The tool surface is significantly incomplete for the stated domain. It includes basic web fetching and documentation search but misses core documentation CRUD operations (e.g., create, update, delete docs) and comprehensive scraping capabilities, leading to potential agent failures in handling full workflows.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Jina AI Reader/Search MCP — turn any URL into clean LLM-ready markdown, plus web search.
Scrape, crawl and search the web for AI agents via MCP.
Web search, URL content extraction to Markdown, site mapping, and recursive web crawler.
Query any docs site via MCP. Submit a URL, ask questions, get cited answers.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables web content retrieval and semantic search capabilities through the Jina AI API. Provides tools to fetch content from URLs and perform intelligent web searches with natural language queries.3MIT
- FlicenseBqualityDmaintenanceEnables intelligent search through FastMCP documentation using TF-IDF indexing, along with utility tools for arithmetic operations, text hashing, and web page content extraction via Jina Reader.4
- AlicenseNot gradedqualityCmaintenanceJina AI Reader/Search MCP that turns any URL into clean LLM-ready markdown and provides web search.11MIT
- FlicenseNot gradedqualityDmaintenanceEnables web search and webpage scraping using Jina AI services.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jcdumlao14/03-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server