Skip to content

Commit 36aa401

Browse files
committed
feat: add MCP resources and prompts (v0.3.0)
Add 4 MCP Resources for direct data lookups: - package://{registry}/{name} - Package info from npm/pypi/crates/go - github://{owner}/{repo} - Repository information - status://{service} - Service health status - changelog://{registry}/{package} - Package changelogs Add 5 MCP Prompts for reusable workflows: - research_package - Comprehensive package evaluation - debug_error - Error debugging assistance - compare_technologies - Technology comparison - evaluate_repository - GitHub repo evaluation - check_service_health - Multi-service status check Resources enable direct data access without tool calls. Prompts provide pre-built workflows that guide AI assistants.
1 parent 49bb02f commit 36aa401

5 files changed

Lines changed: 321 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.3.0] - 2025-12-03
11+
12+
### Added
13+
- **4 MCP Resources** - Direct data lookups via URI templates:
14+
- `package://{registry}/{name}` - Package info from npm, PyPI, crates.io, or Go modules
15+
- `github://{owner}/{repo}` - Repository information and health metrics
16+
- `status://{service}` - Service health status for 120+ services
17+
- `changelog://{registry}/{package}` - Package release notes and changelogs
18+
19+
- **5 MCP Prompts** - Reusable message templates for common workflows:
20+
- `research_package` - Comprehensive package evaluation (downloads, maintenance, security)
21+
- `debug_error` - Structured error debugging with context and solutions
22+
- `compare_technologies` - Side-by-side technology comparison
23+
- `evaluate_repository` - GitHub repository health and activity assessment
24+
- `check_service_health` - Multi-service status monitoring
25+
26+
### Why Resources & Prompts?
27+
- **Resources** enable direct data access without tool calls - perfect for quick lookups
28+
- **Prompts** provide pre-built workflows that guide AI assistants through complex tasks
29+
- Both follow the MCP specification for better interoperability
30+
1031
## [0.2.0] - 2025-12-03
1132

1233
### Improved
@@ -76,6 +97,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7697
- Configuration documentation
7798
- 40+ design and implementation docs
7899

79-
[Unreleased]: https://github.com/elad12390/web-research-assistant/compare/v0.2.0...HEAD
100+
[Unreleased]: https://github.com/elad12390/web-research-assistant/compare/v0.3.0...HEAD
101+
[0.3.0]: https://github.com/elad12390/web-research-assistant/compare/v0.2.0...v0.3.0
80102
[0.2.0]: https://github.com/elad12390/web-research-assistant/compare/v0.1.0...v0.2.0
81103
[0.1.0]: https://github.com/elad12390/web-research-assistant/releases/tag/v0.1.0

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[![CI](https://github.com/elad12390/web-research-assistant/workflows/CI/badge.svg)](https://github.com/elad12390/web-research-assistant/actions)
77

88
Comprehensive Model Context Protocol (MCP) server that provides web research and discovery capabilities.
9-
Includes 13 tools for searching, crawling, and analyzing web content, powered by your local Docker SearXNG
9+
Includes **13 tools**, **4 resources**, and **5 prompts** for searching, crawling, and analyzing web content, powered by your local Docker SearXNG
1010
instance, the [`crawl4ai`](https://github.com/unclecode/crawl4ai) project, and Pixabay API:
1111

1212
1. `web_search` — federated search across multiple engines via SearXNG
@@ -26,6 +26,21 @@ instance, the [`crawl4ai`](https://github.com/unclecode/crawl4ai) project, and P
2626
All tools feature comprehensive error handling, response size limits, usage tracking, and clear documentation
2727
for optimal AI agent integration.
2828

29+
### MCP Resources (Direct Data Lookups)
30+
31+
- `package://{registry}/{name}` - Package info from npm, PyPI, crates.io, or Go modules
32+
- `github://{owner}/{repo}` - Repository information and health metrics
33+
- `status://{service}` - Service health status for 120+ services
34+
- `changelog://{registry}/{package}` - Package release notes and changelogs
35+
36+
### MCP Prompts (Reusable Workflows)
37+
38+
- `research_package` - Comprehensive package evaluation
39+
- `debug_error` - Structured error debugging with solutions
40+
- `compare_technologies` - Side-by-side technology comparison
41+
- `evaluate_repository` - GitHub repository health assessment
42+
- `check_service_health` - Multi-service status monitoring
43+
2944
## Quick Start
3045

3146
1. **Set up SearXNG** (5 minutes):
@@ -237,6 +252,29 @@ Results are automatically trimmed (default 8 KB) so they stay well within MCP
237252
response expectations. If truncation happens, the text ends with a note reminding the
238253
model that more detail is available on request.
239254

255+
## Resources
256+
257+
MCP Resources provide direct data access via URI templates - perfect for quick lookups without tool calls.
258+
259+
| Resource URI | Description | Example |
260+
| ------------ | ----------- | ------- |
261+
| `package://{registry}/{name}` | Package metadata (version, downloads, license, dependencies) | `package://npm/express` |
262+
| `github://{owner}/{repo}` | Repository info (stars, forks, issues, activity) | `github://facebook/react` |
263+
| `status://{service}` | Service health status | `status://stripe` |
264+
| `changelog://{registry}/{package}` | Release notes and changelogs | `changelog://npm/typescript` |
265+
266+
## Prompts
267+
268+
MCP Prompts are reusable message templates that guide AI assistants through common workflows.
269+
270+
| Prompt | Arguments | Use Case |
271+
| ------ | --------- | -------- |
272+
| `research_package` | `package_name`, `registry` | Evaluate a package before adding it as a dependency |
273+
| `debug_error` | `error_message`, `language` (optional), `framework` (optional) | Debug an error with context and solutions |
274+
| `compare_technologies` | `tech1`, `tech2`, `tech3` (optional), `tech4` (optional), `tech5` (optional) | Compare frameworks, databases, or languages |
275+
| `evaluate_repository` | `owner`, `repo` | Assess a GitHub project's health and activity |
276+
| `check_service_health` | `services` (comma-separated) | Monitor multiple services at once |
277+
240278
## Configuration
241279

242280
Environment variables let you adapt the server without touching code:

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "web-research-assistant"
3-
version = "0.2.0"
4-
description = "Comprehensive MCP server for web research with 13 tools: search, crawl, package info, GitHub stats, error translation, API docs discovery, and more."
3+
version = "0.3.0"
4+
description = "Comprehensive MCP server for web research with 13 tools, 4 resources, and 5 prompts: search, crawl, package info, GitHub stats, error translation, API docs discovery, and more."
55
readme = "README.md"
66
requires-python = ">=3.10"
77
license = {text = "MIT"}

src/searxng_mcp/server.py

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,262 @@ async def check_service_status(
14991499
return result
15001500

15011501

1502+
# =============================================================================
1503+
# RESOURCES - Read-only data lookups
1504+
# =============================================================================
1505+
1506+
1507+
@mcp.resource("package://{registry}/{name}")
1508+
async def get_package_resource(registry: str, name: str) -> str:
1509+
"""
1510+
Get package information from a registry.
1511+
1512+
URI format: package://{registry}/{name}
1513+
Examples:
1514+
- package://npm/express
1515+
- package://pypi/fastapi
1516+
- package://crates/serde
1517+
- package://go/github.com/gin-gonic/gin
1518+
"""
1519+
if registry not in ("npm", "pypi", "crates", "go"):
1520+
return f"Unknown registry: {registry}. Supported: npm, pypi, crates, go"
1521+
1522+
try:
1523+
if registry == "npm":
1524+
info = await registry_client.search_npm(name)
1525+
elif registry == "pypi":
1526+
info = await registry_client.search_pypi(name)
1527+
elif registry == "crates":
1528+
info = await registry_client.search_crates(name)
1529+
else: # go
1530+
info = await registry_client.search_go(name)
1531+
1532+
return _format_package_info(info)
1533+
except httpx.HTTPStatusError as exc:
1534+
if exc.response.status_code == 404:
1535+
return f"Package '{name}' not found on {registry}."
1536+
return f"Failed to fetch {registry} package '{name}': HTTP {exc.response.status_code}"
1537+
except Exception as exc: # noqa: BLE001
1538+
return f"Failed to fetch {registry} package '{name}': {exc}"
1539+
1540+
1541+
@mcp.resource("github://{owner}/{repo}")
1542+
async def get_github_resource(owner: str, repo: str) -> str:
1543+
"""
1544+
Get GitHub repository information.
1545+
1546+
URI format: github://{owner}/{repo}
1547+
Examples:
1548+
- github://microsoft/vscode
1549+
- github://facebook/react
1550+
- github://anthropics/anthropic-sdk-python
1551+
"""
1552+
try:
1553+
repo_info = await github_client.get_repo_info(owner, repo)
1554+
commits = None
1555+
try:
1556+
commits = await github_client.get_recent_commits(owner, repo, count=3)
1557+
except Exception: # noqa: BLE001, S110
1558+
pass
1559+
return _format_repo_info(repo_info, commits)
1560+
except httpx.HTTPStatusError as exc:
1561+
if exc.response.status_code == 404:
1562+
return f"Repository '{owner}/{repo}' not found."
1563+
elif exc.response.status_code == 403:
1564+
return f"Access denied to '{owner}/{repo}'. May be private or rate limited."
1565+
return f"Failed to fetch '{owner}/{repo}': HTTP {exc.response.status_code}"
1566+
except Exception as exc: # noqa: BLE001
1567+
return f"Failed to fetch '{owner}/{repo}': {exc}"
1568+
1569+
1570+
@mcp.resource("status://{service}")
1571+
async def get_service_status_resource(service: str) -> str:
1572+
"""
1573+
Get service health status.
1574+
1575+
URI format: status://{service}
1576+
Examples:
1577+
- status://anthropic
1578+
- status://openai
1579+
- status://github
1580+
- status://stripe
1581+
"""
1582+
import json
1583+
1584+
try:
1585+
status = await service_health_checker.check_service(service)
1586+
return json.dumps(status, indent=2, ensure_ascii=False)
1587+
except Exception as exc: # noqa: BLE001
1588+
return f"Failed to check status for '{service}': {exc}"
1589+
1590+
1591+
@mcp.resource("changelog://{registry}/{package}")
1592+
async def get_changelog_resource(registry: str, package: str) -> str:
1593+
"""
1594+
Get package changelog and release notes.
1595+
1596+
URI format: changelog://{registry}/{package}
1597+
Examples:
1598+
- changelog://npm/react
1599+
- changelog://pypi/fastapi
1600+
"""
1601+
import json
1602+
1603+
if registry not in ("npm", "pypi"):
1604+
return f"Unknown registry: {registry}. Supported: npm, pypi"
1605+
1606+
try:
1607+
changelog = await changelog_fetcher.get_changelog(package, registry, max_releases=5)
1608+
return json.dumps(changelog, indent=2, ensure_ascii=False)
1609+
except Exception as exc: # noqa: BLE001
1610+
return f"Failed to fetch changelog for '{package}': {exc}"
1611+
1612+
1613+
# =============================================================================
1614+
# PROMPTS - Reusable message templates for common research tasks
1615+
# =============================================================================
1616+
1617+
1618+
@mcp.prompt()
1619+
def research_package(
1620+
package: str,
1621+
registry: str = "npm",
1622+
) -> str:
1623+
"""
1624+
Generate a prompt for comprehensive package research.
1625+
1626+
Use this when you want to thoroughly evaluate a package before adding it to your project.
1627+
"""
1628+
return f"""Please research the "{package}" package from {registry} and provide:
1629+
1630+
1. **Overview**: What does this package do? What problem does it solve?
1631+
2. **Popularity & Trust**: Download stats, GitHub stars, maintenance activity
1632+
3. **Security**: Any known vulnerabilities or security concerns?
1633+
4. **Dependencies**: How many dependencies does it have? Any concerns?
1634+
5. **Alternatives**: What are the main alternatives and how does this compare?
1635+
6. **Recommendation**: Should I use this package? Why or why not?
1636+
1637+
Use the package://{registry}/{package} resource to get the package information, then search for additional context about alternatives and community sentiment."""
1638+
1639+
1640+
@mcp.prompt()
1641+
def debug_error(
1642+
error_message: str,
1643+
language: str = "",
1644+
framework: str = "",
1645+
) -> str:
1646+
"""
1647+
Generate a prompt for debugging an error message.
1648+
1649+
Use this when you encounter an error and want help understanding and fixing it.
1650+
"""
1651+
context_parts = []
1652+
if language:
1653+
context_parts.append(f"Language: {language}")
1654+
if framework:
1655+
context_parts.append(f"Framework: {framework}")
1656+
context = "\n".join(context_parts) if context_parts else "Not specified"
1657+
1658+
return f"""I encountered this error and need help debugging it:
1659+
1660+
```
1661+
{error_message}
1662+
```
1663+
1664+
**Context:**
1665+
{context}
1666+
1667+
Please help me:
1668+
1. **Understand**: What does this error mean in plain terms?
1669+
2. **Root Cause**: What typically causes this error?
1670+
3. **Fix**: How can I resolve this issue? Provide code examples if applicable.
1671+
4. **Prevention**: How can I prevent this error in the future?
1672+
1673+
Use the translate_error tool to find relevant Stack Overflow discussions and solutions."""
1674+
1675+
1676+
@mcp.prompt()
1677+
def compare_technologies(
1678+
tech1: str,
1679+
tech2: str,
1680+
use_case: str = "general use",
1681+
) -> str:
1682+
"""
1683+
Generate a prompt for comparing two technologies.
1684+
1685+
Use this when deciding between two frameworks, libraries, or tools.
1686+
"""
1687+
return f"""Please compare **{tech1}** vs **{tech2}** for {use_case}.
1688+
1689+
Analyze the following aspects:
1690+
1691+
1. **Performance**: Speed, resource usage, scalability
1692+
2. **Developer Experience**: Learning curve, documentation, tooling
1693+
3. **Ecosystem**: Community size, available plugins/extensions, job market
1694+
4. **Maintenance**: Release frequency, backward compatibility, long-term viability
1695+
5. **Use Cases**: When to choose one over the other
1696+
1697+
Use the compare_tech tool to gather data, then provide a clear recommendation with reasoning.
1698+
1699+
**My use case**: {use_case}
1700+
1701+
Which one should I choose and why?"""
1702+
1703+
1704+
@mcp.prompt()
1705+
def evaluate_repository(
1706+
owner: str,
1707+
repo: str,
1708+
) -> str:
1709+
"""
1710+
Generate a prompt for evaluating a GitHub repository.
1711+
1712+
Use this when deciding whether to use or contribute to an open source project.
1713+
"""
1714+
return f"""Please evaluate the GitHub repository **{owner}/{repo}** for potential use in my project.
1715+
1716+
Analyze:
1717+
1718+
1. **Health**: Is this project actively maintained? Check recent commits, issue response time, PR activity.
1719+
2. **Quality**: Code quality indicators, test coverage, documentation quality.
1720+
3. **Community**: Number of contributors, community engagement, responsiveness to issues.
1721+
4. **Stability**: Version history, breaking changes, deprecation policy.
1722+
5. **Security**: Any known vulnerabilities? Security policy in place?
1723+
6. **License**: Is the license compatible with my use case?
1724+
1725+
Use the github://{owner}/{repo} resource to get repository information.
1726+
1727+
Provide a clear recommendation: Should I use this project? What are the risks?"""
1728+
1729+
1730+
@mcp.prompt()
1731+
def check_service_health(
1732+
services: str,
1733+
) -> str:
1734+
"""
1735+
Generate a prompt for checking multiple service statuses.
1736+
1737+
Use this when you suspect infrastructure issues or before a deployment.
1738+
Provide comma-separated service names.
1739+
"""
1740+
service_list = [s.strip() for s in services.split(",")]
1741+
resource_calls = "\n".join([f"- status://{s}" for s in service_list])
1742+
1743+
return f"""Please check the health status of the following services:
1744+
1745+
{resource_calls}
1746+
1747+
For each service, report:
1748+
1. **Status**: Operational, degraded, or experiencing issues?
1749+
2. **Active Incidents**: Any ongoing problems?
1750+
3. **Recent History**: Any recent outages or maintenance?
1751+
1752+
If any services are having issues, suggest:
1753+
- Workarounds or alternatives
1754+
- Expected resolution time (if available)
1755+
- Impact on my application"""
1756+
1757+
15021758
def main() -> None:
15031759
"""Entrypoint used by the console script."""
15041760

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)