Open-source MCP server for AI agents: web search, content extraction, and library docs -- 5-strategy scraping, runs without API keys.
Drift inferred · capture-to-capture
- HIGH code analysis flagged committed secret ×2 in n24q02m/wet
- HIGH code analysis flagged committed secret ×2 in n24q02m/wet
- HIGH code analysis flagged committed secret ×2 in n24q02m/wet
- HIGH code analysis flagged committed secret ×2 in n24q02m/wet
- HIGH code analysis flagged committed secret ×2 in n24q02m/wet
- HIGH code analysis flagged committed secret ×2 in n24q02m/wet
- HIGH code analysis flagged committed secret ×2 in n24q02m/wet
tools
-
config
status, set, cache_clear, docs_reindex, warmup, setup_sync, setup_status, setup_skip, setup_reset, setup_complete
-
config__open_relay
Re-trigger the zero-config relay setup flow (prints a fresh relay URL for the browser form). Registered via mcp-core's register_open_relay_tool so an LLM can restart setup without a manual restart.
-
extract
URL -> smart chunks dict (clean_text + markdown + structured_data + code_blocks + metadata) via web-core 5-strategy chain. Batch processing (up to 50 URLs), deep crawling, site mapping, local file con
-
help
Per-tool documentation: search, extract, media, config
-
media
list (discover URLs from gallery pages), download (SSRF-safe). analyze was removed in v2.0.0 -- use imagine-mcp.understand instead
-
search
Web (SearXNG metasearch), news, images, academic research (Scholar / arXiv / PubMed / CrossRef / Semantic Scholar / BASE), library docs (HyDE + FTS5), find similar pages. Includes docs_resolve (librar
analyzed commit 6f073fa · analyzer v33 · 12h ago
skills & prompt files 8
- agent-rules n24q02m-wet-6f073fa/AGENTS.md
- agent-rules n24q02m-wet-6f073fa/CLAUDE.md
- skill n24q02m-wet-6f073fa/skills/compare/SKILL.md
- skill n24q02m-wet-6f073fa/skills/fact-check/SKILL.md
- skill n24q02m-wet-6f073fa/skills/lock-project-stack/SKILL.md
- skill n24q02m-wet-6f073fa/skills/research-topic/SKILL.md
- skill n24q02m-wet-6f073fa/skills/scrape-batch/SKILL.md
- skill n24q02m-wet-6f073fa/skills/wet/SKILL.md
danger signals8
- dynamic code execution eval()/exec() n24q02m-wet-6f073fa/tests/test_console_encoding.py :67
exec(guard, {"sys": fake_sys, "io": io}) # noqa: S102 - trusted project source - suspicious endpoint 169.254.169.254 (cloud metadata) n24q02m-wet-6f073fa/tests/test_docs_coverage.py :100
request = httpx.Request("GET", "http://169.254.169.254/latest/meta-data/") - suspicious endpoint 169.254.169.254 (cloud metadata) n24q02m-wet-6f073fa/tests/test_full_live.py :423
{"action": "extract", "urls": ["http://169.254.169.254/latest/meta-data"]}, - suspicious endpoint 169.254.169.254 (cloud metadata) n24q02m-wet-6f073fa/tests/test_live_mcp.py :466
"urls": ["http://169.254.169.254/latest/meta-data"], - suspicious endpoint 169.254.169.254 (cloud metadata) n24q02m-wet-6f073fa/tests/test_live_protocol.py :377
{"action": "extract", "urls": ["http://169.254.169.254/latest/meta-data"]}, - suspicious endpoint 169.254.169.254 (cloud metadata) n24q02m-wet-6f073fa/tests/test_security.py :26
assert not is_safe_url("http://169.254.169.254") - committed secret Google OAuth client secret n24q02m-wet-6f073fa/.gitguardian.yaml :12
GOCSPX…(35 chars, redacted) - committed secret Google OAuth client secret n24q02m-wet-6f073fa/src/wet_mcp/config.py :81
GOCSPX…(35 chars, redacted)
code files: 229
filesystem 85
- fs (weak) n24q02m-wet-6f073fa/scripts/benchmark_quality.py :21
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/scripts/build_tier1_index.py :28
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/scripts/cf_full_flow.py :54
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/scripts/deploy_cf.py :68
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/scripts/gen_cf_corpus.py :5
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/scripts/preserve-diacritics.py :22
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/scripts/test_preserve_diacritics.py :15
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/alembic/env.py :19
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/cache.py :15
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/config.py :5
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/db.py :18
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/llm.py :7
from pathlib import Path
show 28 more
- fs n24q02m-wet-6f073fa/src/wet_mcp/migrations.py :24
import shutil - fs n24q02m-wet-6f073fa/src/wet_mcp/security.py :14
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/server.py :22
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/setup.py :14
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/setup_tool.py :9
import shutil - fs n24q02m-wet-6f073fa/src/wet_mcp/sources/crawler.py :24
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/sources/interact_orchestrator.py :26
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/sources/project_lock.py :19
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/sync/base.py :19
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/sync/gdrive.py :26
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/sync/s3.py :23
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/token_store.py :16
from pathlib import Path - fs n24q02m-wet-6f073fa/src/wet_mcp/transport_check.py :21
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/compare_tools.py :16
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/conftest_cf.py :7
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/conftest_e2e.py :84
with open(self._path, encoding="utf-8", errors="replace") as f: - fs (weak) n24q02m-wet-6f073fa/tests/run_benchmark.py :308
with open(out_path, encoding="utf-8") as f: - fs (weak) n24q02m-wet-6f073fa/tests/search_quality/run_baseline.py :12
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/search_quality/test_run_baseline.py :3
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/test_alembic_offline.py :8
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/test_api_keys_security.py :63
os.unlink(tmp_path) - fs (weak) n24q02m-wet-6f073fa/tests/test_benchmark_quality.py :6
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/test_boost_coverage.py :17
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/test_cf_e2e.py :6
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/test_cf_full_flow.py :4
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/test_compose_layering.py :1
import shutil - fs (weak) n24q02m-wet-6f073fa/tests/test_config.py :436
from pathlib import Path - fs (weak) n24q02m-wet-6f073fa/tests/test_console_encoding.py :17
from pathlib import Path
45 more not shown — this panel samples each group; the count above is the real total.
shell / exec 17
- shell (weak) n24q02m-wet-6f073fa/scripts/deploy_cf.py :63
import subprocess - shell (weak) n24q02m-wet-6f073fa/scripts/preserve-diacritics.py :19
import subprocess - shell n24q02m-wet-6f073fa/src/wet_mcp/server.py :321
import subprocess - shell n24q02m-wet-6f073fa/src/wet_mcp/setup.py :12
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/conftest_e2e.py :17
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_boost_coverage.py :15
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_compose_layering.py :2
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_coverage_misc.py :15
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_deploy_cf_migrations.py :21
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_e2e.py :569
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_live_protocol.py :12
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_no_stale_package_name.py :3
import subprocess
show 5 more
- shell (weak) n24q02m-wet-6f073fa/tests/test_real_comprehensive.py :319
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_searxng_runner_comprehensive.py :4
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_setup_comprehensive.py :1
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_stdio.py :8
import subprocess - shell (weak) n24q02m-wet-6f073fa/tests/test_stdio_direct.py :16
import subprocess
network 47
- net (weak) n24q02m-wet-6f073fa/scripts/benchmark_quality.py :23
from urllib.parse import urlsplit - net (weak) n24q02m-wet-6f073fa/scripts/cf_full_flow.py :53
import urllib.parse - net (weak) n24q02m-wet-6f073fa/scripts/deploy_cf.py :66
import urllib.error - net n24q02m-wet-6f073fa/src/wet_mcp/credential_state.py :516
import httpx - net n24q02m-wet-6f073fa/src/wet_mcp/relay_setup.py :131
import httpx - net n24q02m-wet-6f073fa/src/wet_mcp/reranker.py :17
from urllib.parse import urlsplit, urlunsplit - net n24q02m-wet-6f073fa/src/wet_mcp/searxng_runner.py :57
import socket - net n24q02m-wet-6f073fa/src/wet_mcp/server.py :24
from urllib.parse import urlparse - net n24q02m-wet-6f073fa/src/wet_mcp/sources/_search_polish.py :28
from urllib.parse import urlparse - net n24q02m-wet-6f073fa/src/wet_mcp/sources/crawler.py :26
from urllib.parse import urljoin, urlparse - net n24q02m-wet-6f073fa/src/wet_mcp/sources/docs.py :24
from urllib.parse import urljoin, urlparse - net n24q02m-wet-6f073fa/src/wet_mcp/sources/search_backends.py :22
from urllib.parse import unquote, urlparse
show 28 more
- net n24q02m-wet-6f073fa/src/wet_mcp/sources/search_strategies.py :5
from urllib.parse import urlparse - net n24q02m-wet-6f073fa/src/wet_mcp/sources/searxng.py :12
import httpx - net n24q02m-wet-6f073fa/src/wet_mcp/sync/gdrive.py :29
import httpx - net (weak) n24q02m-wet-6f073fa/tests/benchmark_docs_search.py :442
"tests_aspect": "PyPI, aiohttp.readthedocs.io", - net (weak) n24q02m-wet-6f073fa/tests/compare_tools.py :18
import httpx - net (weak) n24q02m-wet-6f073fa/tests/conftest_cf.py :25
from urllib.parse import unquote - net (weak) n24q02m-wet-6f073fa/tests/integration/test_multi_user_remote.py :74
monkeypatch.setattr("httpx.post", _fake_post) - net (weak) n24q02m-wet-6f073fa/tests/search_quality/run_baseline.py :14
from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit - net (weak) n24q02m-wet-6f073fa/tests/test_boost_coverage.py :222
patch("httpx.AsyncClient") as mock_httpx, - net (weak) n24q02m-wet-6f073fa/tests/test_cf_e2e.py :86
with unittest.mock.patch("httpx.AsyncClient.post") as post: - net (weak) n24q02m-wet-6f073fa/tests/test_coverage_misc.py :19
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_crawler_comprehensive.py :6
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_crawler_download.py :4
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_credential_state.py :444
patch("httpx.post", return_value=mock_httpx_response), - net (weak) n24q02m-wet-6f073fa/tests/test_docs_comprehensive.py :4
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_docs_coverage.py :12
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_e2e.py :572
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_media_tool.py :133
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_multiuser_llm_gate_and_backend.py :685
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_real_comprehensive.py :158
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_relay_searxng_and_cf_gdrive.py :52
with patch("httpx.post") as mock_post: - net (weak) n24q02m-wet-6f073fa/tests/test_relay_setup.py :148
patch("httpx.AsyncClient") as mock_httpx, - net (weak) n24q02m-wet-6f073fa/tests/test_search_backends.py :4
import httpx - net (weak) n24q02m-wet-6f073fa/tests/test_search_backends_extended.py :4
Unit tests mock ``httpx.AsyncClient`` and assert SHAPE (request form/headers, - net (weak) n24q02m-wet-6f073fa/tests/test_search_backends_multikey.py :30
with mock.patch("httpx.AsyncClient.post", new=fake_post): - net (weak) n24q02m-wet-6f073fa/tests/test_search_region_refine.py :55
with unittest.mock.patch("httpx.AsyncClient.post") as post: - net (weak) n24q02m-wet-6f073fa/tests/test_search_strategies.py :533
"Use requests.get(url) to make GET requests." - net (weak) n24q02m-wet-6f073fa/tests/test_searxng_auth.py :69
with patch("httpx.AsyncClient", return_value=client):
7 more not shown — this panel samples each group; the count above is the real total.
secrets 14
- secrets (weak) n24q02m-wet-6f073fa/scripts/cf_full_flow.py :66
pw = os.environ.get("MCP_RELAY_PASSWORD") - secrets n24q02m-wet-6f073fa/src/wet_mcp/embedder.py :162
if os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY"): - secrets n24q02m-wet-6f073fa/src/wet_mcp/llm.py :78
if os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY"): - secrets n24q02m-wet-6f073fa/src/wet_mcp/server.py :392
if not (os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")): - secrets n24q02m-wet-6f073fa/src/wet_mcp/sources/docs.py :39
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN") - secrets (weak) n24q02m-wet-6f073fa/tests/compare_tools.py :132
api_key = os.environ.get("CONTEXT7_API_KEY", "") - secrets (weak) n24q02m-wet-6f073fa/tests/test_api_keys_security.py :42
assert os.environ.get("TEST_KEY") == "123" - secrets (weak) n24q02m-wet-6f073fa/tests/test_config.py :158
assert os.environ["GOOGLE_API_KEY"] == "abc" - secrets (weak) n24q02m-wet-6f073fa/tests/test_credential_state.py :98
assert os.environ.get("GEMINI_API_KEY") == "from-file" - secrets (weak) n24q02m-wet-6f073fa/tests/test_credential_state_stdio_no_fallback.py :71
assert os.environ.get("GEMINI_API_KEY") is None - secrets (weak) n24q02m-wet-6f073fa/tests/test_per_plugin_storage_migration.py :46
assert mod.os.environ.get("GEMINI_API_KEY") == "fake-key" - secrets (weak) n24q02m-wet-6f073fa/tests/test_per_sub_credential_isolation.py :42
assert os.environ.get("JINA_AI_API_KEY") is None
show 2 more
- secrets (weak) n24q02m-wet-6f073fa/tests/test_real_comprehensive.py :27
LLM_API_KEY = os.environ.get("LLM_API_KEY", "") - secrets (weak) n24q02m-wet-6f073fa/tests/test_reranker.py :216
assert os.environ["JINA_AI_API_KEY"] == "jina-single-user-key"
database 16
- db n24q02m-wet-6f073fa/src/wet_mcp/alembic/env.py :22
from sqlalchemy import create_engine, event, pool - db n24q02m-wet-6f073fa/src/wet_mcp/cache.py :13
import sqlite3 - db n24q02m-wet-6f073fa/src/wet_mcp/db.py :13
import sqlite3 - db n24q02m-wet-6f073fa/src/wet_mcp/migrations.py :25
import sqlite3 - db n24q02m-wet-6f073fa/src/wet_mcp/sync/base.py :17
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/conftest_cf.py :6
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_d1_schema.py :1
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_d1_schema_0002.py :8
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_db.py :11
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_db_add_chunks_serialization.py :1
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_db_coverage.py :10
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_migrations.py :17
import sqlite3
show 4 more
- db (weak) n24q02m-wet-6f073fa/tests/test_migrations_coverage.py :3
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_silent_failure_surfacing.py :16
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_sync_wal_checkpoint.py :19
import sqlite3 - db (weak) n24q02m-wet-6f073fa/tests/test_tier1_index_embedding_identity.py :26
import sqlite3
declared dependencies 12
- fastmcp@>=3.4.7,<5
- google-api-python-client@>=2.198.0
- google-auth@>=2.56.2
- boto3@>=1.43.56
- waitress@>=3.0.2; sys_platform ==
- github.com/gin-gonic/gin@v1.10.0
- github.com/spf13/cobra@v1.8.0
- github.com/labstack/echo/v4@v4.12.0
- tokio@1.40
- serde@1.0
- clap@4.5
- criterion@0.5