Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

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.

GitHubEmbed

Описание

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

README

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:

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.

from github.com/pypi-ahmad/add-an-llm-to-your-mcp-server

Установка Local Intelligence Server

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/pypi-ahmad/add-an-llm-to-your-mcp-server

FAQ

Local Intelligence Server MCP бесплатный?

Да, Local Intelligence Server MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Local Intelligence Server?

Нет, Local Intelligence Server работает без API-ключей и переменных окружения.

Local Intelligence Server — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить Local Intelligence Server в Claude Desktop, Claude Code или Cursor?

Открой Local Intelligence Server на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Local Intelligence Server with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории ai