Drop NickServ identification

Not registering clod with NickServ, so remove the IDENTIFY-on-connect code,
the nickserv_password_file setting and its .gitignore entry. The periodic
attempt to reclaim clod from clod_ stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
weishaupt
2026-10-11 11:03:42 -04:00
co-authored by Claude Opus 5.5
parent fc973790fb
commit 6a62ce1758
4 changed files with 2 additions and 29 deletions
-1
View File
@@ -1,4 +1,3 @@
.venv/ .venv/
__pycache__/ __pycache__/
*.pyc *.pyc
nickserv_password.txt
-1
View File
@@ -3,7 +3,6 @@
A small MCP server that gives Claude Code an IRC connection. A small MCP server that gives Claude Code an IRC connection.
- Connects to `irc.rizon.net:6697` over TLS as `clod`. If that nick is taken it uses `clod_` and tries to switch back every `nick_retry_seconds` (default 180) - Connects to `irc.rizon.net:6697` over TLS as `clod`. If that nick is taken it uses `clod_` and tries to switch back every `nick_retry_seconds` (default 180)
- Identifies to NickServ whenever it holds `clod`, using the password in `nickserv_password.txt` (gitignored, set by `nickserv_password_file`)
- Answers server PINGs, sends its own keepalive PING, and reconnects automatically - Answers server PINGs, sends its own keepalive PING, and reconnects automatically
- Can only join channels listed in `allowed_channels` in `config.json` (re-read on every call, so edits apply right away) - Can only join channels listed in `allowed_channels` in `config.json` (re-read on every call, so edits apply right away)
- Keeps a rolling buffer of recent messages per joined channel (`buffer_size`, default 200) - Keeps a rolling buffer of recent messages per joined channel (`buffer_size`, default 200)
-1
View File
@@ -8,6 +8,5 @@
"realname": "Claude Code IRC MCP", "realname": "Claude Code IRC MCP",
"allowed_channels": ["#blog", "#/g/tv"], "allowed_channels": ["#blog", "#/g/tv"],
"buffer_size": 200, "buffer_size": 200,
"nickserv_password_file": "nickserv_password.txt",
"nick_retry_seconds": 180 "nick_retry_seconds": 180
} }
+2 -26
View File
@@ -5,8 +5,8 @@ messages, and exposes tools to join/leave/send/read/list users.
It never sends chat text on its own: the only things it writes to the server It never sends chat text on its own: the only things it writes to the server
unprompted are protocol traffic (NICK/USER registration, PONG replies, unprompted are protocol traffic (NICK/USER registration, PONG replies,
keepalive PINGs, NickServ IDENTIFY, periodic NICK attempts to reclaim the keepalive PINGs, periodic NICK attempts to reclaim the configured nick, and
configured nick, and re-joining channels you already joined after a reconnect). re-joining channels you already joined after a reconnect).
""" """
import asyncio import asyncio
@@ -47,24 +47,10 @@ def load_config() -> dict:
cfg.setdefault("realname", cfg["nick"]) cfg.setdefault("realname", cfg["nick"])
cfg.setdefault("allowed_channels", []) cfg.setdefault("allowed_channels", [])
cfg.setdefault("buffer_size", 200) cfg.setdefault("buffer_size", 200)
cfg.setdefault("nickserv_password_file", "")
cfg.setdefault("nick_retry_seconds", 180) cfg.setdefault("nick_retry_seconds", 180)
return cfg return cfg
def nickserv_password(cfg: dict) -> str:
"""Read the NickServ password from its (gitignored) file, relative to the config."""
name = cfg["nickserv_password_file"]
if not name:
return ""
path = CONFIG_PATH.parent / name
try:
return path.read_text(encoding="utf-8").strip()
except FileNotFoundError:
log.warning("NickServ password file %s not found; not identifying", path)
return ""
def irc_lower(s: str) -> str: def irc_lower(s: str) -> str:
"""RFC 1459 case folding, used for channel and nick comparison.""" """RFC 1459 case folding, used for channel and nick comparison."""
return s.lower().translate(str.maketrans("[]\\~", "{}|^")) return s.lower().translate(str.maketrans("[]\\~", "{}|^"))
@@ -214,14 +200,6 @@ class IRCClient:
log.info("trying to reclaim nick %s", cfg["nick"]) log.info("trying to reclaim nick %s", cfg["nick"])
await self.send_raw(f"NICK {cfg['nick']}") await self.send_raw(f"NICK {cfg['nick']}")
async def _identify(self):
"""Identify to NickServ, but only while holding the configured (registered) nick."""
cfg = load_config()
password = nickserv_password(cfg)
if password and self._is_me(cfg["nick"]):
log.info("identifying to NickServ as %s", self.nick)
await self.send_raw(f"PRIVMSG NickServ :IDENTIFY {password}")
async def _quit(self): async def _quit(self):
if self.writer: if self.writer:
try: try:
@@ -261,7 +239,6 @@ class IRCClient:
self.registered.set() self.registered.set()
self.status = f"connected as {self.nick}" self.status = f"connected as {self.nick}"
log.info(self.status) log.info(self.status)
await self._identify()
for ch in list(self.wanted): for ch in list(self.wanted):
await self.send_raw(f"JOIN {self.display.get(ch, ch)}") await self.send_raw(f"JOIN {self.display.get(ch, ch)}")
elif cmd in ("432", "433", "436") and not self.registered.is_set(): elif cmd in ("432", "433", "436") and not self.registered.is_set():
@@ -310,7 +287,6 @@ class IRCClient:
if self._is_me(src): if self._is_me(src):
self.nick = p[0] self.nick = p[0]
self.status = f"connected as {self.nick}" self.status = f"connected as {self.nick}"
await self._identify()
for ch, nicks in self.joined.items(): for ch, nicks in self.joined.items():
if src in nicks: if src in nicks:
nicks.discard(src) nicks.discard(src)