GeistHaus
log in · sign up

https://valarmorghulis.io/index.xml

rss
28 posts
Polling state
Status active
Last polled May 19, 2026 04:30 UTC
Next poll May 20, 2026 01:24 UTC
Poll interval 86400s
ETag W/"1e0498978e194a47463203398515bf31"

Posts

Run stdio MCP server with Python in Claude Desktop

Mostly, the stdio MCP servers are configurated in claude_desktop_config.json using mcp-remote via node.js . Here are a few notes if you want to run stdio MCP server with Python in Claude Desktop.

run with uv

Use uv run xxx or uv tool run xxx to run a stdio server, the config like

1{
2  "mcpServers": {
3    "your-mcp": {
4      "command": "uv",
5      "args": ["run", "your-mcp-exeutable"]
6    }
7  }
8}

You may change the args to ["tool", "run", "your-mcp-exeutable"] if you are your mcp servers should be run with uv tool. If the mcp server is one of the executables in a package, change args to ["tool", "run", "--from", "your-package", "your-mcp-exeutable"]

https://valarmorghulis.io/tech/202604-run-stdio-mcp-with-python-in-claude-desktop/
OpenClaw matrix plugin setup in docker

The OpenClaw matrix plugin has a npm dependency issue, it will cause error like

1[plugins] matrix: crypto runtime bootstrap failed: Cannot find module '@vector-im/matrix-bot-sdk'  
2Require stack:  
3- /app/extensions/matrix/src/matrix/deps.ts

Use openclaw plugins install @openclaw/matrix as mentioned if OpenClaw official document always result the docker container failed to start. I managed to use matrix in docker with the methods below:

Method 1

Just directly do npm install in matrix extension dir:

1cd /app/extensions/matrix && npm install

You need to ensure "/app/extensions/matrix" for plugins.load.paths in openclaw.json .

https://valarmorghulis.io/tech/202603-openclaw-matrix-plugin-setup-in-docker/
AI Glasses and the eye doctor

"AI Glasses and the eye doctor

Don't take it serious! You can always give code yes to get it cooling down.

https://valarmorghulis.io/comic/202601-ai-glasses-and-the-eye-doctor/
GEO is Not the Next Generation of SEO

In the rapidly shifting landscape of digital marketing, a new buzzword has taken center stage: GEO, or Generative Engine Optimization.

If you read the latest marketing newsletters, you’ll see everyone looking into GEO today. It is being pitched as the shiny "next generation" of SEO—the silver bullet to draw traffic in an era where users are talking to chatbots instead of typing into search bars. However, this narrative is misleading. While the intention behind optimizing for AI is valid, the concept of GEO as it stands today is very ill-constructed.

https://valarmorghulis.io/view/202601-geo-vs-seo/
Python dependencies states managed via uv(illustrated)

Several dependency management file types are available in the Python ecosystem—requirements.txt, uv.lock, pyproject.toml, etc.

With uv, we can handle most of them. Here is a transition graph showing how to move from one state to another using uv commands.

Python dependencies states managed via uv

Note: "libs in env" refers to installed dependencies in a virtual environment created by uv venv.

https://valarmorghulis.io/tech/202511-python-dependencies-states-managed-via-uv/
Deploy models on SGLang with CPU only

If you just want to serve an LLM model with WSL2 on your old laptop, this is for you.

The official document have introduced how to build and run SGLang in CPU with docker. But there several issues with the image built based on the tutorial:

  • SGLang deps on VLLM, which is not installed
  • SGLang code requires NUMA to run

So I build a image to meet the above problems, which is available at https://hub.docker.com/r/metaphorprojects/sglang-cpu .

https://valarmorghulis.io/tech/202508-deploy-models-on-sglang-with-cpu-only/
Run MiniCPM4 with CPU only

This is a guide for serving the MiniCPM4 0.5b model with CPU only(in my laptop WSL Ubuntu 24.04).

The model is served by llama.cpp, and I break down it for several steps.

  • Download the model from hf
1huggingface-cli download openbmb/MiniCPM4-0.5B
  • Install(and compile) the llama.cpp
 1# build llama.cpp
 2git clone https://github.com/ggml-org/llama.cpp.git
 3sudo apt install python3-dev build-essential cmake libcurl4-openssl-dev
 4cmake -B build  
 5cmake --build build --config Release
 6
 7# prepare llama tools
 8uv venv --python=3.12 .venv
 9source .venv/bin/activate
10uv pip install -r requirements/requirements-convert_hf_to_gguf.txt --index-strategy unsafe-best-match
  • Convert the downloaded safetensors model to gguf format
1# the default model location of huggingface-cli
2python convert_hf_to_gguf.py \
3~/.cache/huggingface/hub/models--openbmb--MiniCPM4-0.5B/snapshots/ebf6ddf19764646a49d94e857fb4eb439f35ecfb/ \
4--outfile /path/to/minicpm4-0.5b.gguf
  • Serve the gguf file with llama.cpp
1build/bin/llama-server --model /path/to/minicpm4-0.5b.gguf

Here you can call the model with OpenAI API protocol at http//127.0.0.1:8080/v1 .

https://valarmorghulis.io/tech/202506-run-minicpm4-with-cpu-only/
Call MCP Server(stdio) directly in the shell

stdio is one of the transport mechanisms MCP(Model Context Protocol) natively supports. Actually stdio is the only transport mechanism Claude Desktop supports currently(as in May, 2025). This article will show you how to call a MCP server in the shell, without mcp dev or any third party tools, only with echo > or copying/pasting JSONRPC message directly.

First, let's write a very simple MCP server(get_time.py) to get the current time:

https://valarmorghulis.io/tech/202505-call-mcp-server-stdio-in-the-shell/
Measuring the CPU and Memory Usage for Python subprocess

The article talks about a method for measuring the resources used by a process invoked by subprocess.run or subprocess.Popen.

We can use psutil to get realtime usage data of a process. Using psutil may not provide accurate resource measurements for short-lived processes, as it samples usage at intervals and can miss brief spikes. We want a method to get the final resource usage of a process after it finishes.

The method leverages multiprocessing.Process to wrap the calling of subprocess.run or subprocess.Popen, and get the resource usage by calling resource.getrusage(resource.RUSAGE_CHILDREN) of the wrapper process. For example,

https://valarmorghulis.io/tech/202505-measuring-cpu-memory-python-subprocess/
tac -- the ignored reverse of cat

When grep a very large log file to find the last occurrence of some string, it is much than efficient to back iterate the files from the last line than methods using tail or tail -n.

And I just found tac from coreutils, best suiting the job. tac is the reverse of cat, the job I mentioned above can be done via:

1tac very-large-log-file.log|grep -m 1 some-string

This is very useful. And most important thing is that I didn't realize the solution is lying there ignored in the coreutils all the time.

https://valarmorghulis.io/tech/202503-tac/
Python version of Rust Result Sum Type

I try to implement a Python version of the Result<T, E> sum type in rust which can be used with match/case pattern matching.

The pattern matching with sub-patterns like case Err(e) could be implemented in Python with the __match_args__ dunder attribute. This is how Result[T, E], OK() and Err() defined:

 1import typing
 2
 3T = typing.TypeVar('T')
 4E = typing.TypeVar('E')
 5
 6class Result[T, E]:
 7    __match_args__ = ('_val',)
 8    def __init__(self, val):
 9        self._val = val
10
11class Ok[T](Result[T, ...]):
12    pass
13
14class Err[E](Result[..., E]):
15    pass

Below is the match/case block, note that if you have different types value to match(like different Error types), the guard(if statement behind the case pattern) must be used.

https://valarmorghulis.io/tech/202501-python-version-of-rust-sum-type-result/
Run wasm built with wasm-pack with pythonmonkey

I have been trying to run wasm code built with wasm-pack with pythonmonkey,  a Mozilla SpiderMonkey JavaScript engine embedded into the Python Runtime.

Consider a lib.rs as follow:

1use wasm_bindgen::prelude::*;  
2  
3#[wasm_bindgen]
4pub fn add(a: i32, b: i32) -> i32 {  
5  return a + b; 
6}

With wasm-pack, we can build the src code to wasm

1wasm-pack build --target nodejs --no-typescript

We will get a .wasm file and a .js wrapper file. The case here is that we can not instantiate the .wasm directly, which will get us errors like No module named '__wbindgen_placeholder__', or import object field '__wbindgen_init_externref_table' is not a Function. We should instead import the .js wrapper file, and use exported interfaces.

https://valarmorghulis.io/tech/202501-wasm-with-pythonmonkey/
Combine mesop with natural abilities of flask

mesop is popular with AI apps, since is can be used to build web apps with Python without frontend works.

mesop is developed upon the popular frontend framework flask. How about combine the natural abilities of flask while developing with mesop? Let do a little research.

Access flask request instance(including headers, cookies)

In any mesop page, you may simply access flask.request, flask.request.cookies, flask.request.headers by importing flask. For example

 1import flask
 2import mesop as me
 3
 4@me.page(
 5    path="/home",
 6    security_policy=me.SecurityPolicy(  
 7        dangerously_disable_trusted_types=True)  
 8)  
 9def page():  
10    with me.box():  
11        for k, v in flask.request.cookies.items():
12            me.text(f'{k}: {v}')

The above code will display the cookies inside a box component.

https://valarmorghulis.io/tech/202412-mesop-flask-app/
Create a partial model definition of a pydantic model

Sometimes I want to create a partial model definition of a pydantic model. For example, if I want to expose a database model from API, some of the fields I would like to keep in secret, or I just want to expose very few fields in a summary API. I don't want to write model definition twice. I would like to write something like

1ModelExposed = partial_model(ModelSource, 'ModelExposed', include=["title", "description"])

So I write a funciton as below to do it, including support of passing list of excluding fields, copying computed fields and validators.

https://valarmorghulis.io/tech/202412-pydantic-partial-model/
psql vs. mysql shell command cheatsheet
MySQL Postgres list databases SHOW DATABASES \l change to a database USE <db_name> \c <db_name> list tables SHOW TABLES \dt describe a table DESC <table_name> \d <table_name> show the create table sql SHOW CREATE TABLE <table_name> pg_dump -st <table_name> <db_name> explain a query EXPLAIN <sql_statement> EXPLAIN <sql_statement> expanded(vertical) display \G \gx
or use \x to switch get help ? <SQL STATEMENT>
HELP <SQL STATEMENT> \h <SQL STATEMENT> get active processes SHOW [FULL] PROCESSLIST; SELECT pid, usename, state, query, query_start, application_name FROM pg_stat_activity WHERE state = 'active'; kill a process KILL <pid>; SELECT pg_terminate_backend(<pid>); quit shell QUIT \q
https://valarmorghulis.io/tech/202412-psql-vs-mysql-shell-cheatsheet/
Deploy next.js using pm2 cluster mode(and with docker)

We can simply start the Next.js application using next start. However, when facing higher traffic demands in practical use, how can we deploy Next.js using a multi-process approach?

We can achieve this using the cluster mode of pm2. The cluster mode is a powerful way of scaling Node.js applications, allowing you to start multiple processes, all listening on the same port. How do we do this? First, we can create a .json file to describe the pm2 task (named pm2.json):

https://valarmorghulis.io/tech/202409-next-js-using-pm2-cluster-mode/
Use python -m http.server in SSL

python -m http.server is a very convenient command line tool to start an ad-hoc static web server. This tool is very useful when you want to develop small web applications or serve static files.

But it does not support SSL. A lot of modern web applications as well as browser features require a secured connection. So I want to wrap http.server in SSL and try making it simple to use.

https://valarmorghulis.io/tech/202409-python-http-serveri-in-ssl/
The contextvars and the chain of asyncio tasks in Python

In Python, the contextvars is somehow like thread local, but mostly for coroutines. But will the context itself be kept consistent in a chain of asyncio tasks? Let's find out.

contextvars

Let's have a rough review of the contextvars in Python. The contextvars module provides a way to maintain a context across a chain of function calls, natively supported with asyncio. For example

 1import asyncio
 2import contextvars
 3
 4var = contextvars.ContextVar('var', default={})
 5
 6async def sub2():
 7    print(f'in sub2, {var.get()=}')
 8    var.set('sub1 set')
 9
10async def sub1():
11    print(f'in sub1, {var.get()=}')
12    var.set('sub1 set')
13    await sub2()
14
15async def main():
16    var.set('main set')
17    await sub1()
18    print(f'in main, {var.get()=}')
19
20asyncio.run(main())

The output would be

https://valarmorghulis.io/tech/202408-the-asyncio-tasks-and-contextvars-in-python/
Unix pipe to clipboard with WSL, and in UTF-8

WSL is good, it will be even better if we can pipe stdout directly into Windows host’s clipboard. Just like

1    ./myscript.sh | to-my-clipboard.sh

Note that xclip requires X, so it is not an option. From WSL, we have direct access to Windows executables. The easiest method would be using clip.exe:

1    ./myscript.sh | clip.exe

The method works fine if you don’t touch CJK characters or emojis. clip.exe didn’t handle the encoding well since the default codepage in Windows is not 65001(UTF-8). The command below would probably break

https://valarmorghulis.io/tech/202404-unix-pipe-to-clipboard-with-wsl-and-in-utf8/
Several tips for better working with Python in Excel

After enrolled for Python in Excel preview, now I can type =py( in any Excel cell to write some Python code. Python in Excel doesn't have detailed documents, only Get Started tutorials, like link 1, link 2, or articles talking about topics like pandas, matplotlib, seaborn, etc., it may confuse you when you want to do some real work in an unfamiliar environment. The article notes several tips from my understanding of Python in Excel.

https://valarmorghulis.io/tech/202310-python-in-excel/
Analyze robots.txt with Python Standard Library

If haven't searched both "python" and "robots.txt" in the same input box, I would not ever know that Python Standard Library could parse robots.txt with urllib.robotparser.

But the official document of urllib.robotparser doesn't go into detail. With the document, you could check whether a url can be fetch with a robot with robot_parser_inst.can_fetch(user_agent, url) if you are building a crawler bot yourself. But if you want to do some statistics about robots.txt, like what most disallowed path for Googlebot are, from the document not only you don't know how to do it, but also you don't know whether the lib is able to do it.

https://valarmorghulis.io/tech/202309-analyze-robotstxt-with-python/
Process AWS Kinesis Firehose data with Python

Pipelining streamed data events directly into Amazon S3 via the AWS Kinesis Firehose service is convenient and efficient. And we could use Python with boto3 to consume the data directly from S3. This allows for seamless storage of your data, ensuring its integration and accessibility.

Mostly, we are dealing with JSON-formatted event logs. But there is one tiny stone in the shoe for logs feeding from AWS Kinesis Firehose, there is no newline between consecutive log entries.

https://valarmorghulis.io/tech/202309-aws-firehose-json-python/
Thoughts on the fading away of the age of IE

Nowadays, as it pleased most frontend engineers, making web pages/applications compatible with IE Browser is not required almost everywhere.

Internet Explorer, especially the lower versions, is inconsistent with W3C standards, barely has developer toolchains, and therefore very hard to debug. But the anti-modern frontend legacy browsers didn’t easily die. If you had checked browser distribution in recent years, you would notice that IE always had a reasonable proportion, not much, but also not in a trend towards zero in a short period.

https://valarmorghulis.io/view/202307-thoughts-on-the-fading-away-of-the-age-of-ie/
The curious cases of json_extract

json_extract is a function for extract data from a JSON document both in MySQL and MariaDB. The function normally works fine, for example

1set @j = '{"num": 42, "list": [1, 2, 3], "obj": {"name": "Edward Stark"}}'; 
2select json_extract(@j, '$.num') as num, json_extract(@j, '$.list') as list, json_extract(@j, '$.obj') as obj;
3 
4+------+-----------+--------------------------+
5| num  | list      | obj                      |
6+------+-----------+--------------------------+
7| 42   | [1, 2, 3] | {"name": "Edward Stark"} |
8+------+-----------+--------------------------+

But when it comes to a single JSON string, the results of json_extract is not always as expected. We shall investigate the different cases.

https://valarmorghulis.io/tech/202004-the-curious-cases-of-json-extract/
Contextvars and Thread local

Here in the post, I will share some examples about the contextvars (new in Python 3.7) and thread local.

Default Value

In the module level, use ContextVar.set or directly setattr for a thread local variable, won't successfully set a default value, the value set won't take effect in another thread.

To ensure a default value, for contextvars

1import contextvars
2context_var = contextvars.ContextVar("context_var", default=0)

for thread local, a sub class of thread.local need to be declared

https://valarmorghulis.io/tech/201904-contextvars-and-thread-local/
The Tiny Chips from Chinese Hackers: When Falsifiability meets Public Perception

from https://pixabay.com/en/processor-cpu-computer-chip-board-2217771/

During the 2018 Chinese National Day Holidays, Bloomberg Business Week reported that Chinese hackers planted microchips into motherboards supplying for data center servers of tech giants Apple and Amazon. The original Bloomberg post is available at https://www.bloomberg.com/news/features/2018-10-04/the-big-hack-how-china-used-a-tiny-chip-to-infiltrate-america-s-top-companies, and Amazon, Apple, Super Micro and the Chinese Government all have denied the hack.

As I followed the related posts, I found despite there may(or may not) be a hack on the motherboard chips, surely the event happening and growing is a big hack on the public perception. The story of tiny chip hacking is falsifiable in the lab of tech giants like Amazon or Apple, but the story itself spreading in the public, the ongoing process, is not falsifiable. There will never be clear yes/no for the story(even the yes/no could be very sure at the lab), as more and more people read the story(and followed posts), forget the detail or even a summary of the story, remember only some keywords at last, there will be untrustworthy about the chips and conspiracy theories about hackers in the public perception.

https://valarmorghulis.io/view/20181028-the-tiny-chips-from-chinese-hackers/
The Ponzi Software Development Scheme

The metaphor Ponzi Software Development Scheme, came to me after I have been read about a post from CACM, The Death of Big Software. The traditional big softwares will die away, because they are easily growing to become too hard to maintain, and will be replaced by cloud or microservices architecture based softwares.

But will cloud or microservices save big software projects from failure? I rather say, no silver bullets, neither cloud nor microservices. Actually, here the “big” software projects are misleading, software projects fails not because they are big(big repos of code, big set of connected components, big set of requirements/features), software projects fails when they fall into the Ponzi software development scheme. Of course, big software projects are prone to evolve into the Ponzi software development scheme.

https://valarmorghulis.io/view/20180107-the-ponzi-software-development-scheme/
Mongodb(via MongoEngine) join query with aggregate

Since Mongodb 3.2 and MongoEngine 0.9, we can use $aggregate command to perform join queries on multiple collections in a database. This post would be a simple tutorial for join queries on Mongodb(via MongoEngine in Python) with examples.

Models Setup

Let's consider models defined as below:

 1import random
 2import mongoengine
 3
 4
 5class User(mongoengine.Document):
 6    meta = {"indexes": ['rnd']}
 7    name = mongoengine.StringField()
 8    rnd = mongoengine.FloatField(default=random.random)
 9
10
11class Group(mongoengine.Document):
12    meta = {"indexes": ['rnd']}
13    name = mongoengine.StringField()
14    rnd = mongoengine.FloatField(default=random.random)
15
16
17class Relation(mongoengine.Document):
18    meta = {"indexes": ['user_id', 'group_id']}
19    user_id = mongoengine.ObjectIdField()
20    group_id = mongoengine.ObjectIdField()

Note:

https://valarmorghulis.io/tech/201701-mongodb-join-query-with-aggregate/