Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
IT Security NachrichtenOnePlus/OxygenOS: Schad-App erhält Root-Zugriff ohne Berechtigungen(24.09.2026 um 23:38 Uhr)
•
IT Security NachrichtenRyuk Member Karen Vardanyan Sentenced to Two Years in U.S. Prison(24.09.2026 um 22:50 Uhr)
•••••
Hacking & PentestingRyuk Member Karen Vardanyan Sentenced to Two Years in U.S. Prison(24.09.2026 um 22:50 Uhr)
•
AI & KI NachrichtenWhy the U.N. Still Matters(24.09.2026 um 23:00 Uhr)
•••
IT Security NachrichtenOnePlus/OxygenOS: Schad-App erhält Root-Zugriff ohne Berechtigungen(24.09.2026 um 23:38 Uhr)
•
IT Security NachrichtenRyuk Member Karen Vardanyan Sentenced to Two Years in U.S. Prison(24.09.2026 um 22:50 Uhr)
•••••
Hacking & PentestingRyuk Member Karen Vardanyan Sentenced to Two Years in U.S. Prison(24.09.2026 um 22:50 Uhr)
•
AI & KI NachrichtenWhy the U.N. Still Matters(24.09.2026 um 23:00 Uhr)
•••
Intelligence View
⚡ tsecurity.de Intelligence

How to Build a Python MCP Server to Consult a Knowledge Base

Let's say you have a blog that you want to be able to consult from your AI assistant like Claude, how would you do it? In today's world of AI-powered tools, the easiest way would be to create an MCP (Model Context Protocol) server that can…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Let's say you have a blog that you want to be able to consult from your AI assistant like Claude, how would you do it? In today's world of AI-powered tools, the easiest way would be to create an MCP (Model Context Protocol) server that can access the blog in some way and find what you are looking for.



I often use my own blog as a source of information. I think of it as my public field notebook, the only issue with that is that my blog is not "searchable", it doesn't have a built-in search feature, so I often use the site:jtemporal.com <topic> Google search trick to find what I'm looking for.



I have also been using AI assistants like Claude for writing and editing my content, and with the rise of MCP I'd love to search my own content through the chat instead of interrupting my flow to search for information on a separate application.



In order to make this information available we will build an MCP server in Python and learn how to configure it in Claude Desktop. Let's get started, shall we?






How our MCP server works



Our MCP server will run locally and act as a bridge between Claude and the blog content:



Diagram showing the interaction between Claude and the MCP server



This flow shows how Claude can access your blog content using SerpAPI and how it can obtain the content of a given blog post without you ever leaving your conversation by leveraging the MCP server. That means you don't have to switch between interfaces and break your flow.






What Is Model Context Protocol (MCP)



The Model Context Protocol (MCP) is an open standard that enables AI applications to securely connect to external data sources and tools. Think of it as a bridge between your AI assistant and various resources. For the GenAI-powered apps using an MCP, it doesn't really matter what the resources are, they could be files, databases, APIs, or in our case, blog posts stored in a GitHub repository.



MCP allows AI models to:




  • Access external data through standardized interfaces

  • Use tools to perform actions on your behalf

  • Maintain security boundaries between the AI and your data



In our case, we'll use MCP to give our AI assistant the ability to search through blog posts, making your personal knowledge base accessible without having to switch contexts.




src="LinkCard"

title="An Introduction to MCP and Authorization"

link="https://auth0.com/blog/an-introduction-to-mcp-and-authorization/"

description="Discover the Model Context Protocol (MCP) and its authorization mechanisms. Learn how to use API keys, OAuth 2.1 implementation, and best practices for secure LLM API connections."

img="https://images.ctfassets.net/23aumh6u8s0i/ImPbKVGMqKM4FMs9Flncw/f715edcaec63105c95189125436cc3a1/MCP_and_Authorization.jpg"

/>





Model Context Protocol (MCP) SDKs and other libraries



MCP already has a few SDKs you can start using. For this blog post we will use the MCP Python SDK.



We'll also use the SerpApi library to search for blog posts without needing to manage search infrastructure ourselves. SerpApi provides a simple API for performing site-specific Google searches, which is perfect for finding content on your blog.



For package management, we'll use uv, a modern Python package manager that's significantly faster than pip and handles virtual environments automatically. Using uv will also make it easier to setup the server within Claude.





Setting Up the Application



Let's get our MCP server up and running using uv:




  1. Install uv: you can learn how to do that on your system on the uv docs.


  2. Clone the repository: For this tutorial, you can follow along by cloning the repository which contains the setup for the code we'll build:




   git clone https://github.com/jtemporal/blog-search-mcp-in-python.git
cd blog-search-mcp-in-python
git switch base-app







  1. Initialize the project with uv: This creates a virtual environment and installs dependencies



   uv sync







  1. Configure your blog repository settings by copying the example configuration file like so:



   cp .config.example .config





Then edit .config to match your blog details:




   [MCP_SERVER]
blog_base_url = https://yourblog.com
serpapi_key = your-serpapi-key-here
server_name = Blog Search Server
log_level = INFO






To get the SerpApi key sign up for free here.

If you don't have a blog with llms.txt feel free to use mine: jtemporal.com





  1. Test the setup



   uv run pytest tests/test_config.py -v





If you set everything up correctly, all 10 tests should pass. This validates that your configuration is loaded properly and the MCP server can access your settings.



That's it! The code is ready, let's update the MCP server and make sure we can use it in Claude. The uv approach automatically handles virtual environments and dependency management, making the setup much cleaner and more reliable.





Code structure



Our MCP server project has a clean, organized structure like this:




mcp-with-python-blog/
├── src/
│ ├── server.py # Main MCP server implementation
│ └── config.py # Configuration loader
├── tests/ # All tests
├── .config # Your blog configuration
├── .config.example # Configuration template
├── pyproject.toml # Python project configuration and dependencies
├── uv.lock # Dependency lock file
└── README.md # Development documentation






Note a few important aspects of our codebase structure:




  1. Test Organization: The test suite in tests/ holds both unit tests with mock data and integration tests. We should run integration tests sparingly as they make real API calls to SerpApi, which count towards your monthly quota and take longer to run.


  2. Configuration Security: The .config file contains sensitive data like your SerpApi key. Keep this file secure and never commit it to version control.


  3. Clean Architecture: The src/server.py file contains the MCP server implementation where we'll define our tools for blog search and content retrieval.







Tool vs. Resources in MCP Servers



If I were to serve this MCP server as part of my website and in the same machine the blog is hosted today, the MCP server would have access to the files used to generate the blog pages. If this were the case we could use a resource like this to retrieve documents:




@mcp.resource("file://documents/{name}")
def read_document(name: str) -> str:
"""Read a document by name."""
# This would normally read from disk
return f"Content of {name}"






From the MCP documentation:




Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects.




But that's not the case. The blog is a simple static generated website using Jekyll, it is built and served through GitHub Pages. With that in mind it makes more sense to use tools and leverage tool calling.



Tools are more powerful than resources since you can use them to perform actions like the one below that sums two numbers:




@mcp.tool()
def sum(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b






But more than that you can also have tools to search for information in any knowledge base, and in this case a collection of blog posts.



In more concrete terms tool calling, in the context of GenAI and MCP, allows an AI model to execute specific functions. This is perfect for our use case where we need to search through blog posts based on user questions.



Read more on secure tool calling with Auth for GenAI here.




src="LinkCard"

title="Tool Calling in AI Agents: Empowering Intelligent Automation Securely"

link="https://auth0.com/blog/genai-tool-calling-intro/"

description="Discover how AI agents are taking center stage by seamlessly integrating with multiple digital tools like Gmail, Calendar, Slack, and Google Drive to be more efficient. Learn why it is important to secure them and how to do it."

img="https://images.ctfassets.net/23aumh6u8s0i/4LrNhImjPcdPVpmCIrhlG9/4efed8dfb26630e6cf48b4a478a1f550/genai-tool-calling-intro.png"

/>





Creating the MCP Server



Navigate to src/server.py. You'll see some imports already in place: these are the libraries we'll use to build our MCP server. Now create the MCP server instance by adding this line at the end of the file:




mcp = FastMCP(name=SERVER_NAME)






The mcp object is our application instance. We'll use this object to define our tools that Claude can call. Next, we'll implement two tools:





  1. search_posts: Search blog posts for specific topics or keywords


  2. get_post_content: Retrieve the full content of a specific blog post






Search posts tool



The first tool we'll implement, searches for blog posts using SerpApi. This tool will leverage Google's search capabilities to find relevant posts on your blog by performing a site-specific search.



Screenshot of the SerpApi website showing a site-specific Google search for 'site:jtemporal.com pyenv' and the corresponding JSON API response on the right



Add the following code to the end of src/server.py:




@mcp.tool()
def search_posts(query: str) -> str:
search = GoogleSearch({
"q": f"site:{BLOG_BASE_URL.strip('https://')} {query}",
"api_key": SERPAPI_KEY
})
search_result = search.get_dict()

if search_result.get("search_metadata").get("status") == "Success":
posts = search_result.get("organic_results", [])
if posts:
result = f"Found {len(posts)} post(s) matching '{query}':\n\n"
for post in posts:
title = post.get("title")
url = post.get("link")
snippet = post.get("snippet")
result += f"**{title}**\n{url}\n{snippet}\n\n"
return result

return f"No posts found matching '{query}'."






Let's break down what is happening:




  1. @mcp.tool(): This decorator registers the function as an MCP tool that your client can call. The decorator automatically makes the function available to the client with proper type information and documentation.


  2. query parameter: This is the search term that users provide when they want to find blog posts. Claude will automatically extract this from the user's request.


  3. SerpApi integration: We create a GoogleSearch object that performs a site-specific search using the site: operator. This limits results to only your blog domain.


  4. Result processing: We extract the organic search results and format them into a readable response with titles, URLs, and snippets that give users a preview of each post.


  5. Error handling: If no results are found or the API call fails, we return an appropriate message rather than crashing.




From an user perspective this is what happens when this tool is called:



Mermaid Sequence Diagram of search_posts tool






Making the MCP Server Runnable



Finally, to make our MCP server runnable we need to add the following at the end of the file:




if __name__ == "__main__":
mcp.run(transport="stdio")






This is the server entrypoint. The transport="stdio" parameter tells the MCP server to communicate through standard input/output streams. This is the recommended transport method for local MCP servers that integrate with desktop applications like Claude Desktop.



When Claude Desktop launches your MCP server, it communicates with it through stdin/stdout, making this transport layer perfect for our use case. In future deployments to cloud environments, you might use different transport methods like HTTP.






Testing the MCP Server with the MCP Inspector



Now you have a tool to work with. Let's use the MCP Inspector to figure out if everything is running as expected. In your terminal run the following command:




npx @modelcontextprotocol/inspector uv run src/server.py






This will use npx to run the MCP inspector, a tool for testing and debugging MCP servers.



On the left, click Connect so the inspector can connect to your server and then switch to the Tools tab on the right. Then click on List Tools, and you should see something like the image below:



The MCP Inspector interface displaying a successful connection to a local Python MCP server. The 'search_posts' tool is listed in the Tools tab.



You can even run a tool from this interface, go on, try it.






Get Post Content Tool



Your current tool can get your blog posts, but after finding a blog post you usually want to investigate the content you find interesting, so it is time to implement a second tool that can obtain a post content. This tool will leverage the llms.txt from the blog.






What is llms.txt?



The llms.txt file is a simple text file that serves as an index of your blog posts in a format optimized for AI consumption. It contains:




  • A header describing the content

  • Links to raw Markdown files hosted on GitHub



It is structured in a way that's easy for both humans and AI to parse. Here's what a typical llms.txt looks like:




# LLM Feed for jtemporal.com

This file contains links to blog posts in Markdown format for easy LLM consumption.

- [How to Handle JWTs in Python](https://raw.githubusercontent.com/jtemporal/jtemporal.github.io/refs/heads/main/_posts/2023-04-06-how-to-handle-jwts-in-python.md)
- [Creating a Travel Diary With Django](https://raw.githubusercontent.com/jtemporal/jtemporal.github.io/refs/heads/main/_posts/2023-03-30-creating-a-travel-diaries-blog-with-django.md)
...






LLMs prefer Markdown as it is less noisy than an HTML would be, also less expensive to process since you'll have fewer embeddings generated by Markdown than you would by HTML.




src="LinkCard"

title="RAG and Access Control: Where do you start?"

link="https://auth0.com/blog/rag-and-access-control-where-do-you-start/"

description="Generative AI is everywhere, and since not every user has access to all data, learn how to use retrieval-augmented generation with fine-grained authorization to ensure that private information stays private."

img="https://images.ctfassets.net/23aumh6u8s0i/79NCborGcFIrAMeaV7G8oi/f9c588c2d05f0828d447e72e1fe825cc/Latam01.jpg"

/>



Add the following code after the first tool and before the if __name__ == "__main__": clause in src/server.py:




@mcp.tool()
def get_post_content(title: str) -> str:
try:
llm_url = f"{BLOG_BASE_URL}/llms.txt"
response = requests.get(llm_url, timeout=10)
response.raise_for_status()

content = response.text
lines = content.split('\n')

raw_url = None
for line in lines:
if line.strip().startswith('#') or not line.strip():
continue
if title in line:
raw_url = line.split('](')[1].strip(')')

if not raw_url:
return f"Post with title '{title}' not found in llm.txt"

content_response = requests.get(raw_url, timeout=10)
content_response.raise_for_status()

return content_response.text

except requests.RequestException as e:
return f"Error fetching content: {str(e)}"
except Exception as e:
return f"Error processing content: {str(e)}"






Let's break down what is happening:




  1. @mcp.tool(): Once again, this decorator registers the function as an MCP tool that Claude can invoke when users want to read full blog post content.


  2. title parameter: This is the blog post title that users want to retrieve. Claude will extract this from the user's request or from search results.


  3. llms.txt integration: We fetch the llms.txt file from your blog, which serves as an index of all your posts with links to their raw Markdown content on GitHub.


  4. Title matching: We search through the llms.txt index to find a post that contains the requested title. This allows for partial matches, making it easier for users to find posts.


  5. Content retrieval: Once we find the matching post, we extract the GitHub raw URL and fetch the full Markdown content directly from GitHub.


  6. Error handling: We handle various error cases like network issues, missing posts, or malformed index files gracefully.




When this tool is called this is what happens:



Mermaid Sequence Diagram of get_post_content tool






Setting Up the MCP Server in Claude Desktop



Now that we have a working MCP server with two tools, let's configure it in Claude Desktop so you can use it for searching your blog posts during your conversations.



Before setting up the server in Claude Desktop, make sure you have:





  1. Completed the server setup from the previous sections (including uv installation)


  2. A working SerpApi key in your .config file


  3. Claude Desktop app installed on your computer






Configuring Claude Desktop



Claude Desktop uses a claude_desktop_config.json file for MCP server configuration. Since we used the MCP SDK there's a easy way to configure our server in Claude, use the following command:




uv run mcp install "src/server.py" --with google-search-results






This will create the configuration file for you. Now restart Claude and check in the preferences if the server is running: Open the Settings, then access the Developer section. If your server is running as expected you should see something like the image below:



The Developer settings section within the Claude Desktop app, showing the 'Blog Search Server' is successfully configured and has a 'running' status.






Testing the search blog tool in Claude



Now open a new conversation and ask something like: "Can search my blog for posts on pyenv?" Claude should identify your intent, recognize pyenv as the query for the search_posts tool, and offer to use it like so:



A user in Claude asking to search for 'pyenv', and the Claude interface showing a confirmation dialog titled 'Claude would like to use this tool' for the search_posts action



After a second you should see a result like this:



The Claude chat interface displaying formatted search results after running the search_posts tool, listing several blog posts related to 'pyenv'.



This means that Claude parsed the result of the search into a readable result for the chat for you.






Testing the post content tool in Claude



In the same conversation ask something like: "Can you get the content for the first post?" This time Claude should identify the get_post_content tool as well as post title and ofer to use the tool passing along the query like so:



The Claude interface showing a confirmation dialog to use the get_post_content tool after the user asked to retrieve the content of a specific post



After a second you should see a result like this:



Claude displaying a summarized version of a blog post's content, including key benefits and main commands, after successfully using the get_post_content tool



This means that Claude parsed the result of the blog post to show it to you. Keep in mind that this is not a copy of the content on the page but what Claude understood from the blog post.



Tip: If you want you can also configure the server in Cursor, we left instructions in the repository's README.md on how to do it.






Recap and Future Steps



You've successfully built a complete MCP server that can search through your blog posts using Python! Here's what we accomplished:



Created a functional MCP server with two tools:





  • search_posts: Site-specific search using SerpApi


  • get_post_content: Full content retrieval via llms.txt indexing



Integrated with modern APIs using SerpApi for reliable search functionality



Implemented content indexing using the llms.txt standard for AI-optimized content access



Added comprehensive error handling and logging for robust operation



Configured Claude Desktop integration for seamless AI-powered blog search






Key benefits





  • Simple local server: SerpApi and llms.txt require minimal setup and you can run it locally


  • Reliable search: Leverages Google's search quality for finding relevant content


  • Fast content access: Direct GitHub raw content fetching bypasses the GitHub API rate limits


  • AI-optimized: llms.txt format is specifically designed for LLM consumption






What's next?



The MCP ecosystem is rapidly growing, and your blog search server is just the beginning. In a future blog post we will cover how to protect your MCP server to avoid abuse and how to deploy it to Claude so you can access it anywhere without having to have the code locally.



The complete code for this blog post is in this repository.



If you are building GenAI applications make sure you are protecting your user's data and giving the right level of access to your LLMs with Auth for GenAI. Sign up for the Auth for GenAI Developer Preview program.



We've been writing a lot on GenAI applications and tool calling, check out the related blog posts section below to continue learning and keep an eye out here or on our Community Forum to learn when the next part of this series go live.

IoC Intelligence (3 Indikatoren)
f715edcaec63105c95189125436cc3a14efed8dfb26630e6cf48b4a478a1f550f9c588c2d05f0828d447e72e1fe825cc
CTI Threat Relationship Graph3 Knoten / 2 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
SOC Incident Playbook: Remote Code Execution (RCE) Defense
Syntax validiert (0 Fehler)
title: Detect Exploitation - How to Build a Python MCP Server to Consult a Knowledge Base
id: 56ba542e-386e-4687-b94e-61148c9642cc
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "How to Build a Python MCP Serv" ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("How to Build a Python MCP Server to Cons")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*How to Build a Python MCP Server to Cons*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "How to Build a Python MCP Server to Cons"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc
🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich How to Build a Python MCP Server to Cons.... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How to Build a Python MCP Server to Consult a Knowledge Base

Thematisch verwandte Begriffe: Build, Python, Server, Consult · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-81473 | Dell Rugged Control Center (RCC), versions prior to 5.2.206, contain an …
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel • Rechts: nächster Artikel • unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...
↗ Original-Quelle