Local Intelligence Server

Local Intelligence Server

Enables offline local LLM analysis of text data via MCP, taking raw text and an instruction to return analysis results without cloud calls.

Category
访问服务器

README

Local Intelligence MCP Server

Offline server-side LLM analysis over the Model Context Protocol

A production-shaped educational project that exposes one MCP tool — analyze_data — which takes arbitrary text plus a natural-language instruction, runs analysis on a local Ollama model (qwen3.5:4b), and returns the result to the MCP client. No cloud LLM calls. No embeddings. No vector database. Inference stays on 127.0.0.1:11434.

Field Value
Protocol MCP via official Python SDK (mcp[cli])
Server name Local Intelligence Server
Tool analyze_data(raw_text: str, instruction: str) -> str
Model qwen3.5:4b (Ollama)
Sampling temperature=0, think=False
Runtime Python 3.13.13 · uv only
Last verified real run 2026-07-11 08:57:55 UTC · quality gate passed

Who this README is for

Audience What you get
Portfolio / technical reviewers Architecture decisions with tradeoffs, reproducibility path, real captured outputs, honest limitations
Hands-on operators Install, run, demo CLI, Inspector, troubleshooting, how to extend tools
Tutorial learners MCP concepts, request lifecycle, why this is not RAG, line-by-line implementation flow

Table of contents

  1. Problem statement
  2. What this project does (and does not do)
  3. Architecture
  4. Architecture decisions (for reviewers)
  5. Conceptual walkthrough (for learners)
  6. Implementation flow
  7. Project layout
  8. Requirements
  9. Installation
  10. Operation
  11. Sample data
  12. Real run — evidence
  13. Troubleshooting
  14. Extending the server
  15. Limitations and known issues
  16. Dependencies
  17. License

1. Problem statement

MCP clients (Claude Desktop, Cursor, custom agents, the MCP Inspector) are excellent at orchestration, but they are not always the right place to hold large raw payloads or to spend tokens re-summarizing noisy logs. Two common patterns emerge:

  1. Client-side analysis — the host model receives the full log dump in its context window, burns tokens, and may leak sensitive lines into a cloud provider.
  2. Cloud tool backends — the MCP server forwards text to a remote API; convenient, but data leaves the machine and costs scale with volume.

This project implements a third pattern:

Server-side local intelligence: the MCP server receives raw_text + instruction, calls a local LLM, and returns a compact analysis string. The client works with the result, not necessarily the full dump.

That pattern is useful for log triage, entity extraction, reformatting messy text, and any workflow where “preprocess offline on the machine that holds the data” matters more than multi-document retrieval.


2. What this project does (and does not do)

Does

  • Run an MCP server named Local Intelligence Server
  • Register exactly one tool: analyze_data
  • Build a fixed chat prompt (system + user) and call Ollama locally
  • Return analysis as a string; convert exceptions into error strings so the client still gets a tool result
  • Provide a reproducible demo (run_demo.py) against real public Loghub samples
  • Document verbatim model outputs from a timed local run

Does not

  • Call OpenAI / Anthropic / any remote chat API
  • Use embeddings (nomic-embed-text, qwen3-embedding, etc.)
  • Implement RAG (chunking, vector index, retriever, reranker)
  • Fine-tune models or use Unsloth / LoRA
  • Expose multiple tools, resources, or prompt templates (Phase 1 scope)

If you need multi-document grounding over a private corpus, that is a different architecture (see §5.4 Why this is not RAG). This repo deliberately stays single-pass.


3. Architecture

┌──────────────────────────────────────────────────────────────────┐
│  MCP Client                                                       │
│  (Inspector UI · Claude Desktop · custom ClientSession · agent)   │
└───────────────────────────────┬──────────────────────────────────┘
                                │  MCP over stdio
                                │  tools/list · tools/call
                                ▼
┌──────────────────────────────────────────────────────────────────┐
│  server.py                                                        │
│  FastMCP("Local Intelligence Server")                             │
│                                                                   │
│  @mcp.tool()                                                      │
│  def analyze_data(raw_text, instruction) -> str                   │
│        │                                                          │
│        ├─ system: "You are a precise data analysis assistant."    │
│        ├─ user:   f"{instruction}\n\n{raw_text}"                  │
│        │                                                          │
│        └─ ollama.chat(                                            │
│             model="qwen3.5:4b",                                   │
│             options={"temperature": 0},                           │
│             think=False,                                          │
│           )                                                       │
│        → response["message"]["content"]  (or error string)        │
└───────────────────────────────┬──────────────────────────────────┘
                                │  HTTP POST /api/chat
                                │  127.0.0.1:11434 only
                                ▼
                     ┌─────────────────────┐
                     │  Ollama daemon       │
                     │  qwen3.5:4b weights  │
                     └─────────────────────┘

Component responsibilities

Layer Component Responsibility
Client Inspector / agent Discover tools, send arguments, display result
Transport MCP stdio JSON-RPC messages between client and server process
Server FastMCP + analyze_data Validate surface, build prompt, call Ollama, shape errors
Runtime Ollama Load model, generate tokens, never leave localhost
Demo harness run_demo.py Feed Loghub slices, call tool + MCP client, write artifacts/

Request lifecycle (one tool call)

  1. Client sends tools/call with name=analyze_data and {raw_text, instruction}.
  2. FastMCP deserializes arguments into the Python function.
  3. The function builds a two-message chat (system + user).
  4. ollama.chat posts to the local daemon; generation runs entirely on-device.
  5. Server returns the assistant content string as the tool result text.
  6. Client renders that text; raw logs need not remain in the client’s long-term context.

4. Architecture decisions (for reviewers)

Each decision below is intentional. Alternatives that were rejected are listed so the design can be evaluated, not just described.

D1 — Official mcp[cli] FastMCP, not the standalone fastmcp package

Chosen Rejected
from mcp.server.fastmcp import FastMCP after uv add "mcp[cli]" Third-party PyPI package named fastmcp (different maintainer lineage)

Why: Tutorial and SDK docs refer to FastMCP bundled inside the official MCP Python SDK. Installing both packages confuses imports and versions. Verified import path against installed mcp 1.28.1.

D2 — Single tool, single pass

Chosen Rejected
One tool analyze_data Tool sprawl (separate summarize / extract / format tools) or multi-agent graphs

Why: Phase 1 teaches “LLM inside an MCP tool.” One well-described tool with free-form instruction covers summarize, extract, format, and pattern-finding without combinatorial API surface. Extra tools can be added later (see §14).

D3 — Local Ollama + fixed model qwen3.5:4b

Chosen Rejected
qwen3.5:4b only Cloud chat APIs; silent fallbacks to other tags; embedding models

Why: Portfolio consistency with other local projects; 4B fits common laptop GPUs/CPU budgets; no API keys in the critical path. The model name is pinned in code so demos do not silently drift.

D4 — temperature=0 and think=False

Setting Rationale Evidence
temperature=0 Log triage is a factual task; lower sampling variance Stable structure across direct vs MCP re-run on same Apache input
think=False Default Qwen3.5 CoT can exhaust the generation budget and return empty message.content while still HTTP 200 A/B on Apache case: default think → 0 content chars / ~39 s; think=False1790 chars / ~7 s (2026-07-11)

Empty content is treated as an error string so clients never receive a silent blank “success.”

D5 — Errors as return values, not raised exceptions

except Exception as e:
    return f"Error calling local LLM: {e}"

Why: MCP tool failures that raise often surface as opaque transport errors. Returning a string keeps the tool contract (-> str) and gives the client something to show the user (e.g. “connection refused to Ollama”).

D6 — uv-only environment, Python 3.13.13

Chosen Rejected
uv venv, uv add, uv run, pin 3.13.13 Raw pip + python -m venv as the primary path

Why: Reproducible lockfile (uv.lock), consistent with the rest of the local portfolio toolchain.

D7 — No RAG in this repo

Retrieval adds index management, chunk quality, embedding cost, and a second failure mode (retrieve-wrong → generate-confidently-wrong). For single blob + instruction analysis, stuffing the blob into the user message is the simplest correct design. Reviewers should judge this as scoped correctness, not missing features.

Decision summary matrix

Concern Decision Primary tradeoff
SDK Official mcp[cli] Slightly heavier install than a micro-server
Model Local 4B Qwen Weaker than frontier cloud models; fully private
Decoding temp 0, no think Less creative; more reliable content field
Scope One tool Less API surface; less specialization
Data plane Logs in tool args Fine for KB-scale slices; not for multi-GB dumps

5. Conceptual walkthrough (for learners)

5.1 What is MCP?

The Model Context Protocol is a standard way for AI applications (hosts/clients) to talk to capability servers. A server can expose:

Primitive Role Used here?
Tools Callable functions with schemas (side effects or computation) Yesanalyze_data
Resources Readable data URIs (files, records) No
Prompts Reusable prompt templates No

Think of MCP like a USB standard for AI tools: the client does not hard-code every vendor API; it lists tools, reads JSON schemas, and calls them.

5.2 Client vs server vs model

Piece Runs where Knows about
MCP client Host app User intent, tool selection, conversation UI
MCP server (server.py) Separate process (stdio) How to call Ollama, how to shape the tool
LLM Ollama process Tokens in → tokens out; no MCP awareness

The model never “speaks MCP.” The server translates MCP tool calls into ollama.chat and back.

5.3 What “server-side analysis” means

Without this server, a typical flow is:

User → Host LLM → (sees full logs in prompt) → answer

With this server:

User → Host LLM → tools/call analyze_data(raw_text, instruction)
                      → Local LLM analyzes
                      → compact string returns
                 → Host LLM uses summary for the user

Benefits:

  • Privacy: raw lines stay on the machine running Ollama.
  • Token budget: host context holds analysis, not megabytes of logs (when the host chooses not to re-paste them).
  • Specialization: the tool’s system prompt is fixed for “precise data analysis.”

5.4 Why this is not RAG (and when you would add it)

RAG (Retrieval-Augmented Generation) is a pipeline roughly:

Query → embed query → vector search over chunks → (optional rerank)
      → stuff top-k chunks into prompt → generate answer
RAG component Purpose In this project?
Document loader Ingest corpus No (client passes text)
Chunker Split long docs No (40-line slices for demos)
Embedding model Map text → vectors No
Vector store Index / search No
Retriever / reranker Select context No
Generator LLM Answer from context Yes — but context is the whole raw_text argument

This project is tool-augmented generation with a local LLM, not RAG. The “context” is supplied explicitly as raw_text. That is the right pattern when:

  • the user (or agent) already has the exact text to analyze, or
  • the corpus is small enough to fit in one call.

You would add RAG when:

  • the knowledge base is large and unknown to the caller,
  • you need citations from many documents,
  • or repeated queries should not re-send the full corpus each time.

A future extension could still live behind MCP (e.g. search_logs tool + analyze_data), but that is out of Phase 1 scope.

5.5 System vs user message design

Role Content Why
system Fixed persona: precise data analysis assistant Stabilizes style and task framing
user {instruction} then blank line then {raw_text} Puts the operator’s goal first; data second

Putting the instruction first helps the model treat the log as evidence for a stated task rather than free-form “continue the log.”

5.6 Temperature and thinking (decoded)

  • Temperature controls randomness. 0 means greedy / near-deterministic decoding — preferred for ops-style extraction.
  • Thinking / CoT (Qwen3.5) can produce a long private reasoning trace. If the runtime budgets tokens primarily for that trace, the visible answer field can be empty. Disabling think keeps tokens for content.

5.7 Stdio transport in one sentence

The MCP host starts uv run mcp run server.py as a child process and speaks JSON-RPC on stdin/stdout. No open network port is required for the default local setup (Inspector adds a local proxy for the browser UI).


6. Implementation flow

Map the code path in server.py to the lifecycle above.

1. Import FastMCP from official SDK
2. Instantiate mcp = FastMCP("Local Intelligence Server")
3. Decorate analyze_data with @mcp.tool()  → schema + description auto-derived
4. On call:
     a. try:
     b.   ollama.chat(model, messages, options, think=False)
     c.   read message.content
     d.   if empty → error string
     e.   else return content
     f. except → error string
5. mcp CLI loads module, finds global `mcp`, runs server.run()

Line-level map (server.py)

Lines Code intent
1–2 Imports: FastMCP + Ollama client
4 Server identity string shown to clients
7–12 Tool registration + docstring (appears in tools/list)
14–15 Comment documenting the empty-content failure mode
16–24 Local chat completion with pinned model and decoding flags
25–28 Content extraction and empty-content guard
29–30 Exception → client-visible error string

There is no if __name__ == "__main__" block. uv run mcp run server.py imports the module, locates the mcp object, and calls run() for you.

Demo harness flow (run_demo.py)

for each Loghub 40-line slice:
    analyze_data(raw, instruction)     # direct Python call
    write artifacts/<id>_direct.txt

MCP ClientSession over stdio:
    list_tools → expect ["analyze_data"]
    call_tool(apache case)
    write artifacts/mcp_stdio_apache.txt

write artifacts/run_summary.json + full_outputs.json
assert quality gate (non-empty, no errors)

7. Project layout

.
├── server.py                 # MCP server + analyze_data
├── run_demo.py               # Reproducible real-run harness
├── main.py                   # uv init stub (unused by MCP path)
├── pyproject.toml            # project metadata + deps
├── uv.lock                   # locked graph
├── .python-version           # 3.13.13
├── LICENSE                   # MIT (code)
├── README.md                 # this file
├── data/
│   ├── SOURCE.md             # Loghub provenance
│   ├── apache_access_sample.log
│   ├── linux_syslog_sample.log
│   ├── hdfs_sample.log
│   ├── apache_40.log         # analysis slice
│   ├── linux_40.log
│   └── hdfs_40.log
└── artifacts/                # outputs from real runs
    ├── run_summary.json
    ├── full_outputs.json
    ├── apache_mod_jk_errors_direct.txt
    ├── linux_ssh_auth_failures_direct.txt
    ├── hdfs_block_activity_direct.txt
    └── mcp_stdio_apache.txt

8. Requirements

Dependency Notes
Linux environment Verified on Ubuntu
uv Package manager and runner
Python 3.13.13 Pinned in .python-version
Ollama Daemon listening locally
Model qwen3.5:4b Must appear in ollama list
Node.js / npx Only for mcp dev (Inspector UI)
ollama list | grep 'qwen3.5:4b'
# expect a line with qwen3.5:4b

9. Installation

# From the project root
uv python install 3.13.13    # if needed; fallback policy is 3.12.10 only if 3.13.13 is unresolvable
uv venv --python 3.13.13
uv python pin 3.13.13
uv sync                      # restores mcp[cli] + ollama from uv.lock

Confirm packages:

uv run python -c "
import importlib.metadata as m
from mcp.server.fastmcp import FastMCP
print('mcp', m.version('mcp'))
print('ollama', m.version('ollama'))
print('FastMCP OK', FastMCP)
"

Expected (as of the documented run): mcp 1.28.1, ollama 0.6.2.


10. Operation

10.1 One-command real demo (recommended first)

With Ollama up and qwen3.5:4b available:

uv run python run_demo.py

This rewrites artifacts/, prints full model outputs, and exits non-zero if the quality gate fails.

10.2 MCP Inspector (browser)

uv run mcp dev server.py

Typical console lines:

Proxy server listening on localhost:6277
MCP Inspector is up and running at:
  http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=...

In the UI:

  1. Confirm transport stdio and command defaults (uv + run --with mcp mcp run server.py).
  2. Connect.
  3. Open Toolsanalyze_data.
  4. Paste log text into raw_text, set instruction, Run Tool.

10.3 Server only (stdio)

uv run mcp run server.py

Useful when a host app launches the server as a subprocess.

10.4 Ad-hoc Python call (no MCP)

uv run python -c "
from pathlib import Path
from server import analyze_data
raw = Path('data/apache_40.log').read_text()
print(analyze_data(raw, 'List unique error messages and approximate counts.'))
"

10.5 Example tool arguments

Argument Example
raw_text Contents of data/linux_40.log
instruction Extract attacking IPs and recommend firewall actions in bullets.

11. Sample data

Real public logs from Loghub (LogPAI), downloaded 2026-07-11. See data/SOURCE.md.

Local full file Upstream Lines Demo slice
data/apache_access_sample.log Apache/Apache_2k.log 1999 data/apache_40.log
data/linux_syslog_sample.log Linux/Linux_2k.log 1999 data/linux_40.log
data/hdfs_sample.log HDFS/HDFS_2k.log 2000 data/hdfs_40.log

Upstream URLs:

  • https://raw.githubusercontent.com/logpai/loghub/master/Apache/Apache_2k.log
  • https://raw.githubusercontent.com/logpai/loghub/master/Linux/Linux_2k.log
  • https://raw.githubusercontent.com/logpai/loghub/master/HDFS/HDFS_2k.log

40-line slices keep prompts inside a practical context budget for a 4B local model while remaining realistic (error storms, SSH noise, healthy HDFS INFO).

License note: Loghub data is third-party. This repo’s MIT license covers project code, not the log corpus.


12. Real run — evidence

12.1 Run metadata

Field Value
Timestamp (UTC) 2026-07-11 08:57:55
Model qwen3.5:4b
Decoding temperature=0, think=False
Packages mcp 1.28.1 · ollama 0.6.2
Network POST http://127.0.0.1:11434/api/chatHTTP 200 on all calls
Quality gate passed (artifacts/run_summary.json"all_ok": true)

12.2 Timing table

Case Invocation path Elapsed Output size Artifact
Apache mod_jk errors direct analyze_data 6.53 s 1790 chars artifacts/apache_mod_jk_errors_direct.txt
Linux SSH auth failures direct analyze_data 10.49 s 2166 chars artifacts/linux_ssh_auth_failures_direct.txt
HDFS block activity direct analyze_data 9.08 s 2499 chars artifacts/hdfs_block_activity_direct.txt
Apache (same case) MCP stdio tools/call 8.52 s 1790 chars artifacts/mcp_stdio_apache.txt

MCP path also listed tools as ['analyze_data'] with isError: false. Direct and MCP Apache outputs matched (same structure and length under think=False + temperature=0).


12.3 Case 1 — Apache httpd / mod_jk (failure storm)

Input sample (data/apache_40.log):

[Sun Dec 04 04:47:44 2005] [notice] workerEnv.init() ok /etc/httpd/conf/workers2.properties
[Sun Dec 04 04:47:44 2005] [error] mod_jk child workerEnv in error state 6
[Sun Dec 04 04:51:08 2005] [notice] jk2_init() Found child 6725 in scoreboard slot 10
...
[Sun Dec 04 04:51:18 2005] [error] mod_jk child workerEnv in error state 6

Instruction: summarize dominant failure pattern; list unique errors + counts; suggest root cause from evidence only.

Model output (verbatim, 6.53 s):

### 1. Dominant Failure Pattern
The dominant failure pattern is the continuous cycling of Apache JK (mod_jk) backend workers into an **unrecoverable "error" state** despite repeated initialization attempts by `workerEnv.init()`. While new child processes are successfully spawned and registered in the scoreboard, they consistently fail to transition from a healthy or transient error state 6 directly to a stable operational state.

### 2. Unique Error Messages and Approximate Counts
Based on the provided log snippet:

*   **`[error] mod_jk child workerEnv in error state 6`** (Approximately 10 occurrences)
    *   This is the most frequent specific error, appearing repeatedly across different timestamps (e.g., at 04:51:18 and 04:52:15). It indicates a persistent failure condition where the worker cannot recover.
*   **`[error] mod_jk child workerEnv in error state 7`** (Approximately 3 occurrences)
    *   This appears as an escalation or alternative manifestation of the same underlying issue, seen specifically at timestamp `04:52:15`.

*(Note: The logs also contain numerous `[notice] jk2_init() Found child...` and `[notice] workerEnv.init() ok ...` messages indicating successful spawning and initial configuration checks.)*

### 3. Most Likely Root Cause
The root cause is likely a **configuration mismatch or resource exhaustion** preventing the JK workers from completing their initialization sequence, as evidenced by `workerEnv.init()` returning "ok" while the subsequent state check immediately reports an error in states 6 and 7. This suggests that although the Apache process starts successfully, the backend application (Java/Tomcat) running within these children fails to bind or start due to missing ports, insufficient memory, or a deadlock during startup logic.

Reviewer note: counts are approximate model estimates, not deterministic regex tallies. Good for triage; not a substitute for grep -c.

MCP re-run: same case via ClientSession produced the same analysis body (artifacts/mcp_stdio_apache.txt, 8.52 s, isError=false).


12.4 Case 2 — Linux syslog SSH noise

Input sample (data/linux_40.log):

Jun 14 15:16:01 combo sshd(pam_unix)[19939]: authentication failure; ... rhost=218.188.2.4
Jun 15 02:04:59 combo sshd(pam_unix)[20882]: authentication failure; ... rhost=220-135-151-1.hinet-ip.hinet.net  user=root

Model output (verbatim, 10.49 s):

### 1) Security-Relevant Events Identified
*   **SSH Authentication Failures:** Multiple repeated failures detected via `sshd(pam_unix)` indicating brute-force or credential stuffing attempts against the root user (`user=root`).
    *   Source: Jun 15 02:04:59 (IP: 220-135-151-1.hinet-ip.hinet.net) – **7 instances**.
    *   Source: Jun 15 12:12:34 & 12:13:19 (IP: 218.188.2.4) – **Multiple instances** (~16 total).
*   **Successful Privilege Escalation:** Two `su` sessions opened by root (`uid=0`) for non-root users, indicating successful compromise or authorized admin activity.
    *   User: `cyrus` (Jun 15 04:06:18–20).
    *   User: `news` (Jun 15 04:12:42–43).

### 2) Distinct Remote Hosts/IPs Involved in Auth Failures
*   **220-135-151-1.hinet-ip.hinet.net** (IPv6 mapped notation for `220.135.151.1`) – Associated with high-volume root login attempts at 02:04 UTC on Jun 15.
*   **218.188.2.4** (IPv4) – Associated with repeated authentication failures starting Jun 14 and continuing through the morning of Jun 15.

### 3) Non-Auth System Events
*   **Service Activity:** Successful `su` sessions for users `cyrus` and `news`.
*   **Log Rotation Alert:** `logrotate: ALERT exited abnormally with [1]` at Jun 15 04:06:20. This indicates a configuration or disk space issue preventing log rotation, which may be causing syslog buffer issues given the high volume of auth logs generated during the attack window.

### 4) Ops Triage Recommendation
*   **Immediate Action:** Block both remote IPs (`218.188.2.4` and `220-135-151-1.hinet-ip.hinet.net`) at the firewall level immediately to stop active credential stuffing attacks on root accounts.
*   **Investigation Priority 1 (Compromise):** Verify if users `cyrus` or `news` were authorized by an admin who used their credentials for `su`. If unauthorized, assume a successful breach and initiate incident response procedures (reset passwords, audit user activity).
*   **Log Management:** Investigate the `logrotate` failure. With such high log volume from SSH attacks, disk space exhaustion is likely; ensure logs are being archived or rotated to prevent system instability during future attack waves.

Honest limitation: labeling su as possible “compromise” is over-inference — the log alone does not prove unauthorized access. A careful operator treats that as a hypothesis, not a finding of fact. The IP extraction and auth-failure theme are well grounded.


12.5 Case 3 — HDFS healthy INFO traffic

Model output (verbatim, 9.08 s):

Based on the provided HDFS NameNode/DataNode style logs, here is the analysis:

### 1. Summary of Block/Packet Operations
The log snippet depicts a standard **block replication and storage lifecycle** within an HDFS cluster. The operations observed include:
*   **Block Allocation:** New blocks are being allocated for tasks (specifically `/user/root/rand/_temporary/...`), indicated by `NameSystem.allocateBlock`. This suggests active data processing or job execution where new files need to be stored immediately upon creation.
*   **Data Reception & Replication:** Multiple DataNodes (`dfs.DataNode$PacketResponder`) are receiving blocks from various remote peers (e.g., `/10.251.x.x`). The consistent block size of `67108864` bytes indicates standard 64MB replication chunks.
*   **Storage Registration:** As data is received, the NameNode (`dfs.FSNamesystem`) updates its in-memory map to track these blocks as "stored," linking specific DataNodes (e.g., `10.251.73.220:50010`) to their respective block IDs via `NameSystem.addStoredBlock`.
*   **Verification:** A single instance of successful verification (`dfs.DataBlockScanner`), confirming data integrity for a specific block ID before it was likely committed or moved in the broader context (though this log only shows success).

### 2. Unique Components and Thread Names
The logs contain explicit thread/component identifiers following the standard Hadoop logging format `Component$Subcomponent`. The unique components identified are:
*   **dfs.DataNode$PacketResponder**: Handles incoming block data packets for specific blocks or general termination of responder threads.
*   **dfs.FSNamesystem**: Manages high-level filesystem operations, including adding stored blocks to the map and allocating new blocks.
*   **dfs.DataNode$DataXceiver**: Specifically handles the network reception stream (`Receiving block ... src: ... dest: ...`).
*   **dfs.DataBlockScanner**: Responsible for verifying data integrity (checksums) of specific blocks.

*(Note: While timestamps like `081109` and thread IDs in packet responders exist, they are not unique component names).*

### 3. Health Status Assessment
**The snippet looks healthy.**

*   **Evidence:** All log entries are prefixed with the level `INFO`. There are no lines containing `WARN`, `ERROR`, or any other severity indicators indicating a failure or warning condition. The operations (allocation, reception, verification) completed successfully without interruption in this timeframe.

Why this case matters: a useful analyzer must also say “healthy” when appropriate, not invent incidents. The model correctly treated an INFO-only window as non-alarming.


12.6 Reproducibility checklist

Step Command / artifact
Environment uv sync + Python 3.13.13
Model present ollama list includes qwen3.5:4b
Data present data/*_40.log from Loghub slices
Run uv run python run_demo.py
Expect all_ok: true in artifacts/run_summary.json
Compare Outputs may vary slightly across Ollama versions; structure and themes should match

13. Troubleshooting

Symptom Likely cause Fix
Error calling local LLM: ... Connection refused Ollama not running ollama serve or start the desktop service; check port 11434
Empty or near-empty answers (older code without think=False) CoT consumed generation budget Ensure server.py passes think=False (current code does)
model 'qwen3.5:4b' not found Model not pulled ollama pull qwen3.5:4b — do not silently swap tags if following this repo’s model policy
mcp: command not found outside uv CLI not on bare PATH Always use uv run mcp ...
Inspector fails with npx not found Node missing Install Node.js LTS; only required for mcp dev
Inspector auth 401 on proxy Missing session token Use the URL with MCP_PROXY_AUTH_TOKEN printed at startup; header is x-mcp-proxy-auth: Bearer <token>
Extremely slow first call Model cold load First ollama.chat after boot loads weights; subsequent calls are faster
Quality gate fails in run_demo.py Empty content / Ollama error Read the printed error string; verify model health with a tiny ollama run qwen3.5:4b "ping"
Import error mcp.server.fastmcp Wrong package Uninstall standalone fastmcp if present; reinstall mcp[cli] via uv

Health probes

# Ollama up?
curl -s http://127.0.0.1:11434/api/tags | head

# Tool path only
uv run python -c "from server import analyze_data; print(analyze_data('a=1\nb=2','Sum the numbers'))"

# MCP path only
uv run python run_demo.py

14. Extending the server

Phase 1 is intentionally minimal. Practical extensions:

14.1 Add another tool

@mcp.tool()
def count_error_lines(raw_text: str) -> str:
    """Deterministic count of lines containing ERROR/Error/error."""
    n = sum(1 for line in raw_text.splitlines() if "error" in line.lower())
    return f"error_line_count={n}"

Keep deterministic helpers separate from LLM tools so reviewers can tell which path is probabilistic.

14.2 Optional file-path tool

Accept a path under a sandboxed directory, read with size limits, then call the same chat helper. Always enforce:

  • path confinement (no ../../etc/passwd)
  • max bytes
  • allowlist of extensions

14.3 Toward RAG (only if requirements demand it)

A second-phase design might look like:

index_logs(directory) → chunks + embeddings + store
search_logs(query)    → top-k passages
analyze_data(passages + instruction) → still local generation

That adds embedding model choice, index freshness, and evaluation of retrieval quality separately from generation. Do not fold that complexity into analyze_data without measuring need.

14.4 Host configuration sketch

Example Claude Desktop-style config shape (paths will differ):

{
  "mcpServers": {
    "local-intelligence": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/project", "mcp", "run", "server.py"]
    }
  }
}

15. Limitations and known issues

Be explicit with stakeholders:

  1. Small model qualityqwen3.5:4b can mis-count events, invent root causes, or overstate severity (see SSH su example). Use for triage drafts; verify with grep/metrics for decisions.
  2. No retrieval — the model only sees the text you pass. It cannot “know” logs you did not include.
  3. Context limits — full 2k-line Loghub files are stored for provenance; demos use 40-line slices. Multi-MB dumps need chunking or map-reduce style tooling (not implemented).
  4. Approximate structure, not schema-validated output — return type is free-form str, not JSON with Pydantic validation.
  5. Latency — several seconds per call on local hardware (see timing table); not a sub-100ms API.
  6. Single-process stdio — classic MCP local pattern; not a multi-tenant HTTP service with authn/z.
  7. Data license ≠ code license — Loghub samples remain under upstream terms.
  8. Nondeterminism residual — even at temperature 0, backend/version changes can alter wording; do not treat outputs as cryptographic.

16. Dependencies

Managed exclusively with uv (pyproject.toml / uv.lock):

Package Version (locked run) Role
mcp[cli] 1.28.1 Official MCP Python SDK, FastMCP, mcp CLI
ollama 0.6.2 Python client for local Ollama HTTP API

Transitive highlights: pydantic, httpx, anyio, Starlette/SSE stack for SDK features.

Not used: standalone fastmcp, Unsloth, embedding libraries, cloud SDKs.


17. License

Project source code and documentation are released under the MIT License.

Sample logs under data/ are from Loghub and are not re-licensed by this repository. See data/SOURCE.md.


Quick reference

# install
uv sync

# prove the stack
uv run python run_demo.py

# interactive MCP
uv run mcp dev server.py

# headless MCP server
uv run mcp run server.py

Bottom line for reviewers: this is a small, fully offline MCP server that correctly places a local LLM behind a single well-scoped tool, ships real Loghub-based evidence, and documents the failure mode (think vs content) that would otherwise look like a silent bug. Scope is intentional; RAG is deliberately out of band until retrieval is a real requirement.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选