matrix-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,51 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, macos-latest]
16
+ python-version: ["3.12", "3.13"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v7
23
+
24
+ - name: Set up Python ${{ matrix.python-version }}
25
+ run: uv python install ${{ matrix.python-version }}
26
+
27
+ - name: Install dependencies
28
+ run: uv sync --all-extras --dev
29
+
30
+ - name: Run tests
31
+ run: uv run pytest
32
+
33
+ - name: Build package
34
+ run: uv build
35
+
36
+ lint:
37
+ runs-on: ubuntu-latest
38
+ steps:
39
+ - uses: actions/checkout@v6
40
+
41
+ - name: Install uv
42
+ uses: astral-sh/setup-uv@v7
43
+
44
+ - name: Set up Python
45
+ run: uv python install 3.12
46
+
47
+ - name: Install dependencies
48
+ run: uv sync --all-extras --dev
49
+
50
+ - name: Run pre-commit (via prek)
51
+ uses: j178/prek-action@v1
@@ -0,0 +1,24 @@
1
+ name: Upload Python Package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ deploy:
9
+ runs-on: ubuntu-latest
10
+ environment:
11
+ name: pypi
12
+ url: https://pypi.org/p/matrix-mcp
13
+ permissions:
14
+ id-token: write
15
+ steps:
16
+ - uses: actions/checkout@v6
17
+ with:
18
+ fetch-depth: 0
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v7
21
+ - name: Build
22
+ run: uv build
23
+ - name: Publish package distributions to PyPI
24
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,11 @@
1
+ .DS_Store
2
+ .venv/
3
+ .ruff_cache/
4
+ .pytest_cache/
5
+ __pycache__/
6
+ *.py[cod]
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+ .matrix-mcp/
11
+ src/matrix_mcp/_version.py
@@ -0,0 +1,33 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-added-large-files
9
+ - id: check-merge-conflict
10
+ - id: debug-statements
11
+
12
+ - repo: https://github.com/astral-sh/ruff-pre-commit
13
+ rev: v0.14.9
14
+ hooks:
15
+ - id: ruff-check
16
+ args: [--fix]
17
+ - id: ruff-format
18
+
19
+ - repo: local
20
+ hooks:
21
+ - id: mypy
22
+ name: mypy (type checker)
23
+ entry: uv run mypy src tests
24
+ language: system
25
+ types: [python]
26
+ pass_filenames: false
27
+
28
+ - id: ty
29
+ name: ty (type checker)
30
+ entry: uv run ty check
31
+ language: system
32
+ types: [python]
33
+ pass_filenames: false
@@ -0,0 +1,7 @@
1
+ # Matrix MCP
2
+
3
+ This repository is a generic Matrix MCP server.
4
+
5
+ Do not include deployment-specific names, internal domains, company names, private OAuth-provider details, private Matrix room IDs, private Matrix user IDs, or production logs in source, docs, tests, commit messages, issues, or pull requests.
6
+
7
+ Keep the package useful for any Matrix homeserver and any MCP client.
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.4
2
+ Name: matrix-mcp
3
+ Version: 0.1.0
4
+ Summary: A Matrix MCP server for connecting coding agents to Matrix and MindRoom conversations.
5
+ Author: MindRoom
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.12
8
+ Requires-Dist: fastmcp>=2.12
9
+ Requires-Dist: mindroom-nio>=0.25
10
+ Requires-Dist: platformdirs>=4.3
11
+ Requires-Dist: pydantic-settings>=2.9
12
+ Requires-Dist: pydantic>=2.11
13
+ Requires-Dist: rich>=14.0
14
+ Requires-Dist: typer>=0.16
15
+ Provides-Extra: dev
16
+ Requires-Dist: mypy>=1.14; extra == 'dev'
17
+ Requires-Dist: pre-commit>=4; extra == 'dev'
18
+ Requires-Dist: pytest-asyncio>=1.0; extra == 'dev'
19
+ Requires-Dist: pytest>=8.4; extra == 'dev'
20
+ Requires-Dist: ruff>=0.13; extra == 'dev'
21
+ Requires-Dist: ty; extra == 'dev'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Matrix MCP
25
+
26
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
27
+ [![CI](https://github.com/mindroom-ai/matrix-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/mindroom-ai/matrix-mcp/actions/workflows/ci.yml)
28
+ [![PyPI](https://img.shields.io/pypi/v/matrix-mcp.svg)](https://pypi.org/project/matrix-mcp/)
29
+ [![Python Versions](https://img.shields.io/pypi/pyversions/matrix-mcp.svg)](https://pypi.org/project/matrix-mcp/)
30
+ [![Docs](https://img.shields.io/badge/docs-plugins-blue)](https://docs.mindroom.chat/plugins/)
31
+ [![MCP](https://img.shields.io/badge/MCP-server-blue)](https://modelcontextprotocol.io/)
32
+
33
+ <img src="https://media.githubusercontent.com/media/mindroom-ai/mindroom/refs/heads/main/frontend/public/logo.png" alt="MindRoom Logo" align="right" width="120" />
34
+
35
+ Local-first Matrix access for MCP clients.
36
+
37
+ Matrix MCP lets Claude Code and other MCP clients read and write Matrix rooms.
38
+ It is intended to make MindRoom conversations available to local coding agents without giving hosted agents access to the local filesystem.
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ uv tool install git+https://github.com/mindroom-ai/matrix-mcp
44
+ ```
45
+
46
+ For local development:
47
+
48
+ ```bash
49
+ uv sync --extra dev
50
+ ```
51
+
52
+ ## Login
53
+
54
+ Matrix SSO:
55
+
56
+ ```bash
57
+ matrix-mcp auth sso https://matrix.example.com
58
+ ```
59
+
60
+ Existing Matrix access token:
61
+
62
+ ```bash
63
+ matrix-mcp auth token https://matrix.example.com @alice:example.com "$MATRIX_ACCESS_TOKEN" --device-id DEVICEID
64
+ ```
65
+
66
+ Password auth, when enabled by the homeserver:
67
+
68
+ ```bash
69
+ matrix-mcp auth password https://matrix.example.com @alice:example.com
70
+ ```
71
+
72
+ Credentials are stored in the user config directory reported by:
73
+
74
+ ```bash
75
+ matrix-mcp config-path
76
+ ```
77
+
78
+ ## Claude Code
79
+
80
+ Add the local MCP server:
81
+
82
+ ```bash
83
+ claude mcp add matrix -- matrix-mcp serve
84
+ ```
85
+
86
+ The server runs over stdio. It does not expose a local HTTP port during normal MCP operation.
87
+
88
+ ## Tools
89
+
90
+ - `matrix_whoami`: show the configured Matrix user/device.
91
+ - `matrix_list_rooms`: list rooms joined by the authenticated user.
92
+ - `matrix_read_room_recent`: read recent text events from a room.
93
+ - `matrix_send_message`: send a text message, optionally as a Matrix thread reply.
94
+
95
+ The tool instructions tell clients to prefer read tools first and only send messages when the user explicitly asks.
96
+
97
+ ## Development
98
+
99
+ ```bash
100
+ uv run --extra dev pytest
101
+ uv run --extra dev ruff check .
102
+ uv run --extra dev ruff format --check .
103
+ uv run --extra dev mypy src tests
104
+ uv run --extra dev ty check
105
+ uv build
106
+ ```
@@ -0,0 +1,83 @@
1
+ # Matrix MCP
2
+
3
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+ [![CI](https://github.com/mindroom-ai/matrix-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/mindroom-ai/matrix-mcp/actions/workflows/ci.yml)
5
+ [![PyPI](https://img.shields.io/pypi/v/matrix-mcp.svg)](https://pypi.org/project/matrix-mcp/)
6
+ [![Python Versions](https://img.shields.io/pypi/pyversions/matrix-mcp.svg)](https://pypi.org/project/matrix-mcp/)
7
+ [![Docs](https://img.shields.io/badge/docs-plugins-blue)](https://docs.mindroom.chat/plugins/)
8
+ [![MCP](https://img.shields.io/badge/MCP-server-blue)](https://modelcontextprotocol.io/)
9
+
10
+ <img src="https://media.githubusercontent.com/media/mindroom-ai/mindroom/refs/heads/main/frontend/public/logo.png" alt="MindRoom Logo" align="right" width="120" />
11
+
12
+ Local-first Matrix access for MCP clients.
13
+
14
+ Matrix MCP lets Claude Code and other MCP clients read and write Matrix rooms.
15
+ It is intended to make MindRoom conversations available to local coding agents without giving hosted agents access to the local filesystem.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ uv tool install git+https://github.com/mindroom-ai/matrix-mcp
21
+ ```
22
+
23
+ For local development:
24
+
25
+ ```bash
26
+ uv sync --extra dev
27
+ ```
28
+
29
+ ## Login
30
+
31
+ Matrix SSO:
32
+
33
+ ```bash
34
+ matrix-mcp auth sso https://matrix.example.com
35
+ ```
36
+
37
+ Existing Matrix access token:
38
+
39
+ ```bash
40
+ matrix-mcp auth token https://matrix.example.com @alice:example.com "$MATRIX_ACCESS_TOKEN" --device-id DEVICEID
41
+ ```
42
+
43
+ Password auth, when enabled by the homeserver:
44
+
45
+ ```bash
46
+ matrix-mcp auth password https://matrix.example.com @alice:example.com
47
+ ```
48
+
49
+ Credentials are stored in the user config directory reported by:
50
+
51
+ ```bash
52
+ matrix-mcp config-path
53
+ ```
54
+
55
+ ## Claude Code
56
+
57
+ Add the local MCP server:
58
+
59
+ ```bash
60
+ claude mcp add matrix -- matrix-mcp serve
61
+ ```
62
+
63
+ The server runs over stdio. It does not expose a local HTTP port during normal MCP operation.
64
+
65
+ ## Tools
66
+
67
+ - `matrix_whoami`: show the configured Matrix user/device.
68
+ - `matrix_list_rooms`: list rooms joined by the authenticated user.
69
+ - `matrix_read_room_recent`: read recent text events from a room.
70
+ - `matrix_send_message`: send a text message, optionally as a Matrix thread reply.
71
+
72
+ The tool instructions tell clients to prefer read tools first and only send messages when the user explicitly asks.
73
+
74
+ ## Development
75
+
76
+ ```bash
77
+ uv run --extra dev pytest
78
+ uv run --extra dev ruff check .
79
+ uv run --extra dev ruff format --check .
80
+ uv run --extra dev mypy src tests
81
+ uv run --extra dev ty check
82
+ uv build
83
+ ```
@@ -0,0 +1,96 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "matrix-mcp"
7
+ dynamic = ["version"]
8
+ description = "A Matrix MCP server for connecting coding agents to Matrix and MindRoom conversations."
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ license = "MIT"
12
+ authors = [{ name = "MindRoom" }]
13
+ dependencies = [
14
+ "fastmcp>=2.12",
15
+ "mindroom-nio>=0.25",
16
+ "platformdirs>=4.3",
17
+ "pydantic>=2.11",
18
+ "pydantic-settings>=2.9",
19
+ "rich>=14.0",
20
+ "typer>=0.16",
21
+ ]
22
+
23
+ [project.optional-dependencies]
24
+ dev = [
25
+ "mypy>=1.14",
26
+ "pre-commit>=4",
27
+ "pytest>=8.4",
28
+ "pytest-asyncio>=1.0",
29
+ "ruff>=0.13",
30
+ "ty",
31
+ ]
32
+
33
+ [project.scripts]
34
+ matrix-mcp = "matrix_mcp.cli:app"
35
+
36
+ [tool.hatch.version]
37
+ source = "vcs"
38
+
39
+ [tool.hatch.build.hooks.vcs]
40
+ version-file = "src/matrix_mcp/_version.py"
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["src/matrix_mcp"]
44
+
45
+ [tool.pytest.ini_options]
46
+ asyncio_mode = "auto"
47
+ testpaths = ["tests"]
48
+
49
+ [tool.ruff]
50
+ line-length = 100
51
+ target-version = "py312"
52
+
53
+ [tool.ruff.lint]
54
+ select = ["ALL"]
55
+ ignore = [
56
+ "D", # pydocstyle
57
+ "ANN", # annotations
58
+ "COM812", # trailing comma
59
+ "ISC001", # implicit string concat
60
+ "T20", # print statements are acceptable for CLI output
61
+ ]
62
+
63
+ [tool.ruff.lint.per-file-ignores]
64
+ "src/matrix_mcp/cli.py" = [
65
+ "B008", # Typer uses Option/Argument defaults intentionally
66
+ "FBT001", # Typer boolean options are command-line flags
67
+ "FBT003", # Typer boolean option defaults are command-line flag defaults
68
+ "PLR0913", # CLI commands naturally expose several command-line options
69
+ "TC003", # Typer resolves annotations at runtime
70
+ ]
71
+ "src/matrix_mcp/config.py" = [
72
+ "S105", # redaction placeholder is intentionally not a real token
73
+ ]
74
+ "tests/*" = [
75
+ "S101", # assert usage is fine in tests
76
+ "PLR2004", # magic values are fine in tests
77
+ "S105", # test tokens
78
+ "S106", # test tokens
79
+ ]
80
+
81
+ [tool.ruff.format]
82
+ quote-style = "double"
83
+
84
+ [tool.mypy]
85
+ python_version = "3.12"
86
+ strict = true
87
+ warn_return_any = true
88
+ warn_unused_configs = true
89
+ packages = ["matrix_mcp"]
90
+
91
+ [[tool.mypy.overrides]]
92
+ module = ["nio"]
93
+ ignore_missing_imports = true
94
+
95
+ [tool.ty.rules]
96
+ unused-ignore-comment = "ignore"
@@ -0,0 +1,8 @@
1
+ """Matrix MCP package."""
2
+
3
+ __all__ = ["__version__"]
4
+
5
+ try:
6
+ from matrix_mcp._version import __version__
7
+ except ImportError:
8
+ __version__ = "0.0.0"
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.1.0'
22
+ __version_tuple__ = version_tuple = (0, 1, 0)
23
+
24
+ __commit_id__ = commit_id = None
@@ -0,0 +1,122 @@
1
+ from __future__ import annotations
2
+
3
+ from http.server import BaseHTTPRequestHandler, HTTPServer
4
+ from urllib.parse import parse_qs, quote, urlencode, urlsplit
5
+
6
+ from nio import AsyncClient, LoginResponse
7
+ from pydantic import BaseModel
8
+
9
+ from matrix_mcp.config import MatrixMCPConfig
10
+
11
+
12
+ class LoginResult(BaseModel):
13
+ homeserver: str
14
+ user_id: str
15
+ device_id: str | None
16
+ access_token: str
17
+
18
+ def to_config(self) -> MatrixMCPConfig:
19
+ return MatrixMCPConfig(
20
+ homeserver=self.homeserver,
21
+ user_id=self.user_id,
22
+ device_id=self.device_id,
23
+ access_token=self.access_token,
24
+ )
25
+
26
+
27
+ def build_sso_redirect_url(*, homeserver: str, redirect_url: str, idp_id: str | None = None) -> str:
28
+ base = homeserver.rstrip("/")
29
+ provider = f"/{quote(idp_id, safe='')}" if idp_id else ""
30
+ query = urlencode({"redirectUrl": redirect_url})
31
+ return f"{base}/_matrix/client/v3/login/sso/redirect{provider}?{query}"
32
+
33
+
34
+ def extract_login_token(query: str) -> str:
35
+ values = parse_qs(query, keep_blank_values=False)
36
+ token = values.get("loginToken", [None])[0]
37
+ if not token:
38
+ msg = "Matrix SSO callback did not include loginToken"
39
+ raise ValueError(msg)
40
+ return token
41
+
42
+
43
+ class SSOCallbackServer:
44
+ def __init__(self, *, host: str = "127.0.0.1", port: int = 8767) -> None:
45
+ self.token: str | None = None
46
+ self.error: Exception | None = None
47
+
48
+ owner = self
49
+
50
+ class CallbackHandler(BaseHTTPRequestHandler):
51
+ def do_GET(self) -> None:
52
+ try:
53
+ owner.token = extract_login_token(urlsplit(self.path).query)
54
+ self.send_response(200)
55
+ self.end_headers()
56
+ self.wfile.write(b"Matrix MCP login complete. You can close this tab.")
57
+ except Exception as exc: # noqa: BLE001
58
+ owner.error = exc
59
+ self.send_response(400)
60
+ self.end_headers()
61
+ self.wfile.write(b"Matrix MCP login failed. Return to the terminal.")
62
+
63
+ def log_message(self, format: str, *_args: object) -> None: # noqa: A002
64
+ del format, _args
65
+
66
+ self._server = HTTPServer((host, port), CallbackHandler)
67
+ self.redirect_url = f"http://{host}:{self._server.server_port}/callback"
68
+
69
+ def wait_for_token(self) -> str:
70
+ self._server.handle_request()
71
+ self._server.server_close()
72
+ if self.error is not None:
73
+ raise self.error
74
+ if self.token is None:
75
+ msg = "Matrix SSO callback did not complete"
76
+ raise RuntimeError(msg)
77
+ return self.token
78
+
79
+
80
+ async def login_with_password(
81
+ *,
82
+ homeserver: str,
83
+ user: str,
84
+ password: str,
85
+ device_name: str = "matrix-mcp",
86
+ ) -> LoginResult:
87
+ client = AsyncClient(homeserver.rstrip("/"), user)
88
+ try:
89
+ response = await client.login(password=password, device_name=device_name)
90
+ finally:
91
+ await client.close()
92
+ if isinstance(response, LoginResponse):
93
+ return LoginResult(
94
+ homeserver=homeserver.rstrip("/"),
95
+ user_id=response.user_id,
96
+ device_id=response.device_id,
97
+ access_token=response.access_token,
98
+ )
99
+ msg = f"Matrix password login failed: {response}"
100
+ raise RuntimeError(msg)
101
+
102
+
103
+ async def login_with_token(
104
+ *,
105
+ homeserver: str,
106
+ login_token: str,
107
+ device_name: str = "matrix-mcp",
108
+ ) -> LoginResult:
109
+ client = AsyncClient(homeserver.rstrip("/"))
110
+ try:
111
+ response = await client.login(token=login_token, device_name=device_name)
112
+ finally:
113
+ await client.close()
114
+ if isinstance(response, LoginResponse):
115
+ return LoginResult(
116
+ homeserver=homeserver.rstrip("/"),
117
+ user_id=response.user_id,
118
+ device_id=response.device_id,
119
+ access_token=response.access_token,
120
+ )
121
+ msg = f"Matrix token login failed: {response}"
122
+ raise RuntimeError(msg)