diff --git a/.gitignore b/.gitignore index e78a461..77ac754 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .venv/ __pycache__/ *.pyc -nickserv_password.txt diff --git a/README.md b/README.md index 17606ea..d4f4445 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ 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) -- 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 - 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) diff --git a/config.json b/config.json index fb4a801..e2aaa64 100644 --- a/config.json +++ b/config.json @@ -8,6 +8,5 @@ "realname": "Claude Code IRC MCP", "allowed_channels": ["#blog", "#/g/tv"], "buffer_size": 200, - "nickserv_password_file": "nickserv_password.txt", "nick_retry_seconds": 180 } diff --git a/server.py b/server.py index 51bb47f..f002383 100644 --- a/server.py +++ b/server.py @@ -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 unprompted are protocol traffic (NICK/USER registration, PONG replies, -keepalive PINGs, NickServ IDENTIFY, periodic NICK attempts to reclaim the -configured nick, and re-joining channels you already joined after a reconnect). +keepalive PINGs, periodic NICK attempts to reclaim the configured nick, and +re-joining channels you already joined after a reconnect). """ import asyncio @@ -47,24 +47,10 @@ def load_config() -> dict: cfg.setdefault("realname", cfg["nick"]) cfg.setdefault("allowed_channels", []) cfg.setdefault("buffer_size", 200) - cfg.setdefault("nickserv_password_file", "") cfg.setdefault("nick_retry_seconds", 180) 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: """RFC 1459 case folding, used for channel and nick comparison.""" return s.lower().translate(str.maketrans("[]\\~", "{}|^")) @@ -214,14 +200,6 @@ class IRCClient: log.info("trying to reclaim nick %s", 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): if self.writer: try: @@ -261,7 +239,6 @@ class IRCClient: self.registered.set() self.status = f"connected as {self.nick}" log.info(self.status) - await self._identify() for ch in list(self.wanted): await self.send_raw(f"JOIN {self.display.get(ch, ch)}") elif cmd in ("432", "433", "436") and not self.registered.is_set(): @@ -310,7 +287,6 @@ class IRCClient: if self._is_me(src): self.nick = p[0] self.status = f"connected as {self.nick}" - await self._identify() for ch, nicks in self.joined.items(): if src in nicks: nicks.discard(src)