{"id":31192257,"url":"https://github.com/jtemporal/blog-search-mcp-in-python","last_synced_at":"2025-10-13T00:20:33.646Z","repository":{"id":312068773,"uuid":"1045658590","full_name":"jtemporal/blog-search-mcp-in-python","owner":"jtemporal","description":"Sample app of MCP built in Python that performs searches on a specific website and retrieves corresponding content","archived":false,"fork":false,"pushed_at":"2025-08-29T15:19:06.000Z","size":50,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-29T23:57:18.291Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://auth0.com/blog/build-python-mcp-server-for-blog-search/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jtemporal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-27T14:17:13.000Z","updated_at":"2025-09-10T19:23:23.000Z","dependencies_parsed_at":"2025-08-28T16:59:24.112Z","dependency_job_id":"8c49d6bd-0dc6-4461-97ee-8a43670cac21","html_url":"https://github.com/jtemporal/blog-search-mcp-in-python","commit_stats":null,"previous_names":["jtemporal/blog-search-mcp-in-python"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jtemporal/blog-search-mcp-in-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtemporal%2Fblog-search-mcp-in-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtemporal%2Fblog-search-mcp-in-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtemporal%2Fblog-search-mcp-in-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtemporal%2Fblog-search-mcp-in-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jtemporal","download_url":"https://codeload.github.com/jtemporal/blog-search-mcp-in-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jtemporal%2Fblog-search-mcp-in-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279013624,"owners_count":26085298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-19T23:54:08.978Z","updated_at":"2025-10-13T00:20:33.624Z","avatar_url":"https://github.com/jtemporal.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MCP Blog Search Server\n\nA Model Context Protocol (MCP) server that allows AI assistants like Claude to search through your blog posts using SerpApi and retrieve content via llms.txt indexing. Built with Python and designed for seamless integration with Claude Desktop.\n\n## Features\n\n- 🔍 **Smart blog search** using SerpApi for reliable, Google-powered search results\n- 📖 **Full content retrieval** via llms.txt indexing and GitHub raw content\n- ⚡ **Fast and lightweight** with minimal dependencies\n- 🔧 **Simple configuration** with just a few required settings\n- 🧪 **Comprehensive testing** with unit, integration, and fixture-based tests\n- 🤖 **Claude Desktop ready** with easy MCP configuration\n\n## Architecture\n\nOur server uses a modern, reliable architecture:\n- **SerpApi** for site-specific blog post search (no complex GitHub API setup)\n- **llms.txt** standard for AI-optimized content indexing\n- **GitHub raw content** for fast markdown retrieval\n- **FastMCP** framework for clean tool definitions\n\n## Quick Start\n\n1. **Clone and setup**:\n   ```bash\n   git clone https://github.com/jtemporal/blog-search-mcp-in-python.git\n   cd blog-search-mcp-in-python\n   uv sync\n   ```\n\n2. **Configure your blog**:\n   ```bash\n   cp .config.example .config\n   # Edit .config with your blog URL and SerpApi key\n   ```\n\n3. **Test the setup**:\n   ```bash\n   uv run pytest tests/test_config.py -v\n   ```\n\n4. **Inspect the server** with MCP Inspector:\n    ```bash\n    npx @modelcontextprotocol/inspector uv run src/server.py\n    ```\n\n## Configuration\n\nCopy `.config.example` to `.config` and update with your blog details:\n\n```ini\n[MCP_SERVER]\nblog_base_url = https://yourblog.com\nserpapi_key = your-serpapi-key-here\nserver_name = Blog Search Server\nlog_level = INFO\n```\n\n### Getting a SerpApi Key\n\n1. Sign up for free at [SerpApi](https://serpapi.com)\n2. Get your API key from the dashboard\n3. Add it to your `.config` file\n\n**Note**: SerpApi provides 100 free searches per month, which is usually sufficient for personal blog searching.\n\n## Testing\n\n### Unit Tests (Fast, Mock Data)\n\n```bash\n# Run all unit tests (default)\nuv run pytest\n\n# Verbose output\nuv run pytest -v\n\n# Run specific test file\nuv run pytest tests/test_server.py -v\n```\n\n### Integration Tests (Real API Calls)\n\n```bash\n# Run integration tests (requires SerpApi key)\nuv run pytest tests/test_integration.py -v -m integration\n\n# Or run manually for detailed output\nuv run python tests/test_integration.py\n```\n\n### Test Structure\n- **Unit tests**: Fast tests with mocked SerpApi responses and fixtures\n- **Integration tests**: Real API calls to SerpApi and GitHub (requires valid API key)\n- **Fixtures**: Test data stored in `tests/fixtures/` for better maintainability\n\n### Test Markers\n- `pytest` - Runs unit tests only (default, integration tests excluded)\n- `pytest -m integration` - Runs integration tests only\n- `pytest -m \"\"` - Runs all tests (unit + integration)\n\n## Development\n\n### Project Structure\n```\nmcp-with-python-blog/\n├── src/\n│   ├── server.py            # Main MCP server with tools\n│   └── config.py            # Configuration management\n├── tests/\n│   ├── fixtures/            # Test data in JSON files\n│   ├── conftest.py          # Pytest fixtures (loads from fixtures/)\n│   ├── test_server.py       # Unit tests with mocked responses\n│   ├── test_config.py       # Configuration loading tests\n│   └── test_integration.py  # Integration tests (real API calls)\n├── blog-post/               # Blog post about this project\n├── .config                  # Your blog configuration\n├── .config.example          # Configuration template\n├── pyproject.toml           # Project configuration and dependencies\n└── uv.lock                  # Dependency lock file\n```\n\n### Running the MCP Server\n\n```bash\n# Run locally for testing\nuv run mcp src/server.py\n```\n\n### Available Tools\n\nThe MCP server provides two main tools:\n\n1. **`search_posts(query: str)`** - Search through blog posts using SerpApi\n   - Performs site-specific Google search\n   - Returns titles, URLs, and excerpts\n   - Example: \"Search for posts about Python\"\n\n2. **`get_post_content(title: str)`** - Get full content of a specific post\n   - Uses llms.txt index to find posts\n   - Fetches raw markdown from GitHub\n   - Supports partial title matching\n   - Example: \"Get content for 'Python Tips'\"\n\n## Claude Desktop Setup\n\nTo use this MCP server with Claude Desktop:\n\n1. **Run the install command**:\n   ```bash\n   uv run mcp install \"src/server.py\" --with google-search-results\n   ```\n   This will create the server configuration within Claude automatically.\n\n2. **Restart Claude Desktop** completely\n\n3. **Test the integration**:\n   - Start a new conversation\n   - Ask: \"Search my blog for posts about Python\"\n   - Claude should offer to use the `search_posts` tool\n\n## Cursor Desktop Setup\n\nTo use this MCP server with Cursor Desktop:\n\n1. **Locate your Cursor MCP config file**:\n   - **macOS**: `~/.cursor/mcp.json`\n   - **Windows**: `%APPDATA%\\Cursor\\mcp.json`\n   - **Linux**: `~/.config/Cursor/mcp.json`\n\n2. **Add the MCP server configuration**:\n   ```json\n   {\n     \"mcpServers\": {\n       \"blog-search\": {\n         \"command\": \"/path/to/uv\",\n         \"args\": [\n           \"run\",\n           \"--python\", \"3.12.11\",\n           \"--with\", \"mcp[cli]\",\n           \"--with\", \"google-search-results\",\n           \"--with\", \"python-dotenv\",\n           \"mcp\",\n           \"run\",\n           \"/absolute/path/to/your/project/src/server.py\"\n         ],\n         \"cwd\": \"/absolute/path/to/your/project\"\n       }\n     }\n   }\n   ```\n\n3. **Update the paths**:\n   - Replace `/path/to/uv` with your uv executable path (find with `which uv`)\n   - Replace `/absolute/path/to/your/project` with your project directory\n\n4. **Restart Cursor** completely and test the integration\n\n## Usage Examples\n\nOnce configured with Claude Desktop, you can:\n\n### Search for Posts\n- *\"Search my blog for posts about Python\"*\n- *\"Find articles related to web development\"*\n- *\"Look for tutorials on data science\"*\n\n### Get Full Content\n- *\"Get the content of the Python tips post\"*\n- *\"Show me the full article about Django\"*\n- *\"Retrieve the content for 'Introduction to Data Science'\"*\n\n### Workflow Integration\n- *\"Search for my post about JWT handling, then summarize the key points\"*\n- *\"Find my Django tutorial and explain the main concepts\"*\n- *\"Look up my Python posts and create a learning roadmap\"*\n\n## Requirements\n\n### For Your Blog\n\nYour blog needs to provide an `llms.txt` file at `https://yourblog.com/llms.txt` that follows this format:\n\n```\n# LLM Feed for yourblog.com\n\nThis file contains links to blog posts in markdown format for easy LLM consumption.\n\n- [Post Title 1](https://raw.githubusercontent.com/username/repo/main/_posts/post1.md)\n- [Post Title 2](https://raw.githubusercontent.com/username/repo/main/_posts/post2.md)\n...\n```\n\nThis file serves as an index that links to the raw markdown content of your posts on GitHub.\n\nIf you don't have a blog or `llms.txt` file feel free to use mine: `https://jtemporal.com`.\n\n## Dependencies\n\n- Python 3.12+\n- `SerpApi` account (free tier available, [sign up here](https://serpapi.com))\n- Blog with llms.txt index (or you can use mine if you prefer: `https://jtemporal.com`)\n- `uv` package manager\n\n## Contributing\n\n1. **Setup development environment**:\n   ```bash\n   git clone https://github.com/jtemporal/mcp-with-python-blog.git\n   cd mcp-with-python-blog\n   uv sync\n   ```\n\n2. **Run tests**: \n   ```bash\n   uv run pytest -v\n   ```\n\n3. **Add tests for new features** in appropriate test files\n\n4. **Update fixtures** in `tests/fixtures/` when adding new test data\n\n5. **Follow the existing code style** and add proper docstrings\n\n### Adding New Fixtures\n\nTest data is stored in `tests/fixtures/` as JSON files:\n- `blog_posts.json` - Sample blog post data\n- `config.json` - Test configuration\n- `serpapi_*.json` - Mock SerpApi responses\n\nTo add new test data, create a JSON file and load it in `conftest.py` using the `load_fixture()` function.\n\n## Troubleshooting\n\n### Common Issues\n\n- **SerpApi key not working**: Verify your key at [SerpApi dashboard](https://serpapi.com/dashboard)\n- **No search results**: Check that your blog URL is correct and publicly accessible\n- **llms.txt not found**: Ensure your blog serves the llms.txt file at the root\n- **Claude Desktop not recognizing server**: Check file paths and restart Claude completely\n\n### Debug Mode\n\nRun the server manually to see detailed logs:\n```bash\nuv run python src/server.py\n```\n\nRun integration tests to verify API connectivity:\n```bash\nuv run python tests/test_integration.py\n```\n\n## License\n\nMIT License - see LICENSE file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjtemporal%2Fblog-search-mcp-in-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjtemporal%2Fblog-search-mcp-in-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjtemporal%2Fblog-search-mcp-in-python/lists"}