librus-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.
- librus_mcp-0.1.0/.github/workflows/ci.yml +32 -0
- librus_mcp-0.1.0/.github/workflows/publish.yml +30 -0
- librus_mcp-0.1.0/.gitignore +68 -0
- librus_mcp-0.1.0/.pre-commit-config.yaml +51 -0
- librus_mcp-0.1.0/.secrets.baseline +143 -0
- librus_mcp-0.1.0/CODE_OF_CONDUCT.md +45 -0
- librus_mcp-0.1.0/CONTRIBUTING.md +84 -0
- librus_mcp-0.1.0/LICENSE +21 -0
- librus_mcp-0.1.0/PKG-INFO +207 -0
- librus_mcp-0.1.0/README.md +182 -0
- librus_mcp-0.1.0/SECURITY.md +27 -0
- librus_mcp-0.1.0/SPEC.md +114 -0
- librus_mcp-0.1.0/pyproject.toml +54 -0
- librus_mcp-0.1.0/secrets.json.template +14 -0
- librus_mcp-0.1.0/src/__init__.py +0 -0
- librus_mcp-0.1.0/src/config.py +74 -0
- librus_mcp-0.1.0/src/librus_client.py +157 -0
- librus_mcp-0.1.0/src/patches.py +73 -0
- librus_mcp-0.1.0/src/server.py +146 -0
- librus_mcp-0.1.0/uv.lock +1691 -0
- librus_mcp-0.1.0/verify_connection.py +56 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
name: Lint and format check
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
run: uv python install 3.12
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: uv pip install -e . --system
|
|
24
|
+
|
|
25
|
+
- name: Ruff check
|
|
26
|
+
run: uvx ruff check src/
|
|
27
|
+
|
|
28
|
+
- name: Ruff format check
|
|
29
|
+
run: uvx ruff format --check src/
|
|
30
|
+
|
|
31
|
+
- name: Bandit security check
|
|
32
|
+
run: uvx bandit -c pyproject.toml -r src/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
id-token: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
publish:
|
|
12
|
+
name: Build and publish to PyPI
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment:
|
|
15
|
+
name: pypi
|
|
16
|
+
url: https://pypi.org/p/librus-mcp
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
run: uv python install 3.12
|
|
25
|
+
|
|
26
|
+
- name: Build package
|
|
27
|
+
run: uv build
|
|
28
|
+
|
|
29
|
+
- name: Publish to PyPI
|
|
30
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
|
|
7
|
+
# Distribution / packaging
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
*.egg
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.env
|
|
15
|
+
.venv
|
|
16
|
+
env/
|
|
17
|
+
venv/
|
|
18
|
+
|
|
19
|
+
# Unit test / coverage reports
|
|
20
|
+
htmlcov/
|
|
21
|
+
.tox/
|
|
22
|
+
.nox/
|
|
23
|
+
.coverage
|
|
24
|
+
.coverage.*
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
coverage.xml
|
|
27
|
+
|
|
28
|
+
# mypy / Pyre type checkers
|
|
29
|
+
.mypy_cache/
|
|
30
|
+
.dmypy.json
|
|
31
|
+
dmypy.json
|
|
32
|
+
.pyre/
|
|
33
|
+
|
|
34
|
+
# pyenv
|
|
35
|
+
.python-version
|
|
36
|
+
|
|
37
|
+
# Secrets
|
|
38
|
+
secrets.json
|
|
39
|
+
|
|
40
|
+
# IDE settings
|
|
41
|
+
.idea/
|
|
42
|
+
.vscode/
|
|
43
|
+
*.swp
|
|
44
|
+
*.swo
|
|
45
|
+
*~
|
|
46
|
+
|
|
47
|
+
# OS files
|
|
48
|
+
.DS_Store
|
|
49
|
+
Thumbs.db
|
|
50
|
+
|
|
51
|
+
# AI coding assistants
|
|
52
|
+
.claude/ # Claude Code
|
|
53
|
+
.gemini/ # Gemini CLI
|
|
54
|
+
.codex/ # OpenAI Codex CLI
|
|
55
|
+
.cursor/ # Cursor
|
|
56
|
+
.windsurf/ # Windsurf
|
|
57
|
+
.aider* # Aider
|
|
58
|
+
.continue/ # Continue.dev
|
|
59
|
+
.codeium/ # Codeium
|
|
60
|
+
.copilot/ # GitHub Copilot
|
|
61
|
+
.augment/ # Augment Code
|
|
62
|
+
.junie/ # JetBrains Junie
|
|
63
|
+
|
|
64
|
+
# Linter / formatter cache
|
|
65
|
+
.ruff_cache/
|
|
66
|
+
|
|
67
|
+
# Logs
|
|
68
|
+
*.log
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
# General file checks
|
|
3
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
4
|
+
rev: v5.0.0
|
|
5
|
+
hooks:
|
|
6
|
+
# Prevent committing large files (default 500KB)
|
|
7
|
+
- id: check-added-large-files
|
|
8
|
+
args: ['--maxkb=500']
|
|
9
|
+
# Prevent committing files with credentials or secrets patterns
|
|
10
|
+
- id: detect-private-key
|
|
11
|
+
# Ensure JSON files are valid
|
|
12
|
+
- id: check-json
|
|
13
|
+
# Ensure TOML files are valid
|
|
14
|
+
- id: check-toml
|
|
15
|
+
# Ensure YAML files are valid
|
|
16
|
+
- id: check-yaml
|
|
17
|
+
# Prevent committing directly to main/master
|
|
18
|
+
- id: no-commit-to-branch
|
|
19
|
+
args: ['--branch', 'main', '--branch', 'master']
|
|
20
|
+
# Ensure files end with a newline
|
|
21
|
+
- id: end-of-file-fixer
|
|
22
|
+
# Remove trailing whitespace
|
|
23
|
+
- id: trailing-whitespace
|
|
24
|
+
# Catch common merge conflict markers
|
|
25
|
+
- id: check-merge-conflict
|
|
26
|
+
# Prevent adding symlinks that point nowhere
|
|
27
|
+
- id: check-symlinks
|
|
28
|
+
|
|
29
|
+
# Block secrets from being committed
|
|
30
|
+
- repo: https://github.com/Yelp/detect-secrets
|
|
31
|
+
rev: v1.5.0
|
|
32
|
+
hooks:
|
|
33
|
+
- id: detect-secrets
|
|
34
|
+
args: ['--baseline', '.secrets.baseline']
|
|
35
|
+
exclude: (uv\.lock|\.secrets\.baseline)$
|
|
36
|
+
|
|
37
|
+
# Python linting
|
|
38
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
39
|
+
rev: v0.11.11
|
|
40
|
+
hooks:
|
|
41
|
+
- id: ruff
|
|
42
|
+
args: ['--fix']
|
|
43
|
+
- id: ruff-format
|
|
44
|
+
|
|
45
|
+
# Security checks for Python code
|
|
46
|
+
- repo: https://github.com/PyCQA/bandit
|
|
47
|
+
rev: 1.8.3
|
|
48
|
+
hooks:
|
|
49
|
+
- id: bandit
|
|
50
|
+
args: ['-c', 'pyproject.toml']
|
|
51
|
+
additional_dependencies: ['bandit[toml]']
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.5.0",
|
|
3
|
+
"plugins_used": [
|
|
4
|
+
{
|
|
5
|
+
"name": "ArtifactoryDetector"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"name": "AWSKeyDetector"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "AzureStorageKeyDetector"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "Base64HighEntropyString",
|
|
15
|
+
"limit": 4.5
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "BasicAuthDetector"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "CloudantDetector"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "DiscordBotTokenDetector"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "GitHubTokenDetector"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "GitLabTokenDetector"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "HexHighEntropyString",
|
|
34
|
+
"limit": 3.0
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "IbmCloudIamDetector"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "IbmCosHmacDetector"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "IPPublicDetector"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "JwtTokenDetector"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "KeywordDetector",
|
|
50
|
+
"keyword_exclude": ""
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "MailchimpDetector"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "NpmDetector"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "OpenAIDetector"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "PrivateKeyDetector"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "PypiTokenDetector"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "SendGridDetector"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "SlackDetector"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "SoftlayerDetector"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "SquareOAuthDetector"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "StripeDetector"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "TelegramBotTokenDetector"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "TwilioKeyDetector"
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
"filters_used": [
|
|
90
|
+
{
|
|
91
|
+
"path": "detect_secrets.filters.allowlist.is_line_allowlisted"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
|
|
95
|
+
"min_level": 2
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"path": "detect_secrets.filters.heuristic.is_indirect_reference"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"path": "detect_secrets.filters.heuristic.is_likely_id_string"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"path": "detect_secrets.filters.heuristic.is_lock_file"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"path": "detect_secrets.filters.heuristic.is_potential_uuid"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"path": "detect_secrets.filters.heuristic.is_sequential_string"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"path": "detect_secrets.filters.heuristic.is_swagger_file"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"path": "detect_secrets.filters.heuristic.is_templated_secret"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"path": "detect_secrets.filters.regex.should_exclude_file",
|
|
126
|
+
"pattern": [
|
|
127
|
+
"(uv\\.lock|\\.secrets\\.baseline|secrets\\.json)$"
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
"results": {
|
|
132
|
+
"secrets.json.template": [
|
|
133
|
+
{
|
|
134
|
+
"type": "Secret Keyword",
|
|
135
|
+
"filename": "secrets.json.template",
|
|
136
|
+
"hashed_secret": "cf109a70a9c73fd9a8061796eedc0d6a8a1d9add",
|
|
137
|
+
"is_verified": false,
|
|
138
|
+
"line_number": 6
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
"generated_at": "2026-03-10T12:19:41Z"
|
|
143
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a positive experience for everyone.
|
|
7
|
+
|
|
8
|
+
## Our Standards
|
|
9
|
+
|
|
10
|
+
Examples of behavior that contributes to a positive environment:
|
|
11
|
+
|
|
12
|
+
- Using welcoming and inclusive language
|
|
13
|
+
- Being respectful of differing viewpoints and experiences
|
|
14
|
+
- Gracefully accepting constructive feedback
|
|
15
|
+
- Focusing on what is best for the community
|
|
16
|
+
- Showing empathy towards other community members
|
|
17
|
+
|
|
18
|
+
Examples of unacceptable behavior:
|
|
19
|
+
|
|
20
|
+
- Trolling, insulting or derogatory comments, and personal attacks
|
|
21
|
+
- Publishing others' private information without explicit permission
|
|
22
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
23
|
+
|
|
24
|
+
## Enforcement Responsibilities
|
|
25
|
+
|
|
26
|
+
Project maintainers are responsible for clarifying and enforcing standards of
|
|
27
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
28
|
+
response to any behavior that they deem inappropriate or harmful.
|
|
29
|
+
|
|
30
|
+
## Scope
|
|
31
|
+
|
|
32
|
+
This Code of Conduct applies within all project spaces, including issues,
|
|
33
|
+
pull requests, and discussions.
|
|
34
|
+
|
|
35
|
+
## Enforcement
|
|
36
|
+
|
|
37
|
+
Instances of unacceptable behavior may be reported to the project maintainer
|
|
38
|
+
at [contact@datacraze.io](mailto:contact@datacraze.io). All complaints will
|
|
39
|
+
be reviewed and investigated promptly and fairly.
|
|
40
|
+
|
|
41
|
+
## Attribution
|
|
42
|
+
|
|
43
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/),
|
|
44
|
+
version 2.1, available at
|
|
45
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Contributing to librus-mcp
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing! This document provides guidelines to make the process smooth for everyone.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Clone your fork and set up the development environment:
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/YOUR_USERNAME/librus-mcp.git
|
|
11
|
+
cd librus-mcp
|
|
12
|
+
uv venv && uv pip install -e .
|
|
13
|
+
```
|
|
14
|
+
3. Create a branch for your change:
|
|
15
|
+
```bash
|
|
16
|
+
git checkout -b your-branch-name
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Development Workflow
|
|
20
|
+
|
|
21
|
+
### Code Style
|
|
22
|
+
|
|
23
|
+
The key rules:
|
|
24
|
+
|
|
25
|
+
- **Safety first:** Validate inputs and outputs with assertions (~2 per function)
|
|
26
|
+
- **Split assertions:** `assert a; assert b` — never `assert a and b`
|
|
27
|
+
- **Functions <= 70 lines**
|
|
28
|
+
- **No abbreviations** in variable names
|
|
29
|
+
- **Comments explain "why"**, not "what"
|
|
30
|
+
- **Lines <= 100 columns**
|
|
31
|
+
|
|
32
|
+
### Linting and Formatting
|
|
33
|
+
|
|
34
|
+
Before submitting, ensure your code passes:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
uvx ruff check src/
|
|
38
|
+
uvx ruff format src/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Testing
|
|
42
|
+
|
|
43
|
+
Run the verification script to confirm basic connectivity works:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python verify_connection.py
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
When adding new functionality, ensure you test it manually against a real Librus account.
|
|
50
|
+
|
|
51
|
+
## Submitting Changes
|
|
52
|
+
|
|
53
|
+
1. Commit your changes with a clear, descriptive message
|
|
54
|
+
2. Push to your fork
|
|
55
|
+
3. Open a Pull Request against `main`
|
|
56
|
+
4. Describe what your change does and why
|
|
57
|
+
|
|
58
|
+
### What Makes a Good PR
|
|
59
|
+
|
|
60
|
+
- **Focused:** One logical change per PR
|
|
61
|
+
- **Documented:** Update README.md if you add/change tools
|
|
62
|
+
- **Linted:** All ruff checks pass with zero warnings
|
|
63
|
+
- **Tested:** You have verified the change works
|
|
64
|
+
|
|
65
|
+
## Adding a New MCP Tool
|
|
66
|
+
|
|
67
|
+
See [SPEC.md](SPEC.md) for the step-by-step process of adding a new tool.
|
|
68
|
+
|
|
69
|
+
## Reporting Bugs
|
|
70
|
+
|
|
71
|
+
Open a GitHub issue with:
|
|
72
|
+
|
|
73
|
+
- What you expected to happen
|
|
74
|
+
- What actually happened
|
|
75
|
+
- Steps to reproduce
|
|
76
|
+
- Your Python version and OS
|
|
77
|
+
|
|
78
|
+
## Security Issues
|
|
79
|
+
|
|
80
|
+
**Do not open public issues for security vulnerabilities.** See [SECURITY.md](SECURITY.md) for responsible disclosure instructions.
|
|
81
|
+
|
|
82
|
+
## Questions?
|
|
83
|
+
|
|
84
|
+
Open a GitHub issue or reach out at [contact@datacraze.io](mailto:contact@datacraze.io).
|
librus_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Krzysztof Bury
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: librus-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for Librus Synergia — access grades, messages, attendance, homework, timetables, and announcements from AI assistants
|
|
5
|
+
Project-URL: Homepage, https://github.com/krzysztoofbury/librus-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/krzysztoofbury/librus-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/krzysztoofbury/librus-mcp/issues
|
|
8
|
+
Author-email: Krzysztof Bury <contact@datacraze.io>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: claude,gemini,gradebook,librus,llm,mcp,synergia
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: librus-apix>=0.1.0
|
|
22
|
+
Requires-Dist: mcp>=0.1.0
|
|
23
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Librus MCP Server
|
|
27
|
+
|
|
28
|
+
[](LICENSE)
|
|
29
|
+
[](https://pypi.org/project/librus-mcp/)
|
|
30
|
+
|
|
31
|
+
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that provides AI assistants with access to the **Librus Synergia** electronic gradebook. It supports multiple student accounts simultaneously and exposes tools for grades, messages, attendance, homework, schedules, timetables, and announcements.
|
|
32
|
+
|
|
33
|
+
## Acknowledgments
|
|
34
|
+
|
|
35
|
+
This project is built on top of the excellent [**librus-apix**](https://github.com/RustySnek/librus-apix) library by [**RustySnek**](https://github.com/RustySnek). Their work on reverse-engineering and maintaining a Python client for the Librus Synergia platform made this MCP server possible. If you find this project useful, please consider starring their repository as well.
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
### 1. Add to your AI assistant
|
|
40
|
+
|
|
41
|
+
Pick your client. Credentials are passed directly via the `env` block — no files or cloning needed.
|
|
42
|
+
|
|
43
|
+
#### Claude Desktop
|
|
44
|
+
|
|
45
|
+
Add to your `claude_desktop_config.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"librus": {
|
|
51
|
+
"command": "uvx",
|
|
52
|
+
"args": ["librus-mcp"],
|
|
53
|
+
"env": {
|
|
54
|
+
"LIBRUS_ACCOUNTS": "[{\"alias\":\"daughter\",\"username\":\"12345\",\"password\":\"...\"}]"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Claude Code
|
|
62
|
+
|
|
63
|
+
Via the `/mcp` command or in `.claude/settings.json`:
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"mcpServers": {
|
|
68
|
+
"librus": {
|
|
69
|
+
"command": "uvx",
|
|
70
|
+
"args": ["librus-mcp"],
|
|
71
|
+
"env": {
|
|
72
|
+
"LIBRUS_ACCOUNTS": "[{\"alias\":\"daughter\",\"username\":\"12345\",\"password\":\"...\"}]"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### Gemini CLI
|
|
80
|
+
|
|
81
|
+
Add to `~/.gemini/settings.json` (global) or `.gemini/settings.json` (project-level):
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"mcpServers": {
|
|
86
|
+
"librus": {
|
|
87
|
+
"command": "uvx",
|
|
88
|
+
"args": ["librus-mcp"],
|
|
89
|
+
"env": {
|
|
90
|
+
"LIBRUS_ACCOUNTS": "[{\"alias\":\"daughter\",\"username\":\"12345\",\"password\":\"...\"}]"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### OpenAI Codex CLI
|
|
98
|
+
|
|
99
|
+
Add to `~/.codex/config.toml` (global) or `.codex/config.toml` (project-level):
|
|
100
|
+
|
|
101
|
+
```toml
|
|
102
|
+
[mcp_servers.librus]
|
|
103
|
+
command = "uvx"
|
|
104
|
+
args = ["librus-mcp"]
|
|
105
|
+
|
|
106
|
+
[mcp_servers.librus.env]
|
|
107
|
+
LIBRUS_ACCOUNTS = '[{"alias":"daughter","username":"12345","password":"..."}]'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
> **Note:** `uvx` automatically downloads and runs the package from PyPI — no cloning or virtual environments needed. You only need [uv](https://github.com/astral-sh/uv) installed (`curl -LsSf https://astral.sh/uv/install.sh | sh`).
|
|
111
|
+
|
|
112
|
+
### Providing credentials
|
|
113
|
+
|
|
114
|
+
Each account represents a **parent's login** to Librus Synergia for a specific child. In the Polish school system, parents receive separate Librus login credentials for each of their children. The `alias` is a friendly name you choose to identify which child's data you're accessing. The `username` and `password` are the parent portal credentials you use to log in at [synergia.librus.pl](https://synergia.librus.pl/).
|
|
115
|
+
|
|
116
|
+
There are three ways to provide credentials (checked in this order):
|
|
117
|
+
|
|
118
|
+
| Method | Best for | Example |
|
|
119
|
+
|--------|----------|---------|
|
|
120
|
+
| `LIBRUS_ACCOUNTS` env var | `uvx` users, CI | JSON array of account objects (see examples above) |
|
|
121
|
+
| `LIBRUS_CONFIG` env var | Custom file location | Path to your `secrets.json`, e.g. `~/.config/librus/secrets.json` |
|
|
122
|
+
| `secrets.json` in working dir | Local development | Create from `secrets.json.template` |
|
|
123
|
+
|
|
124
|
+
#### Multiple children
|
|
125
|
+
|
|
126
|
+
Add multiple accounts to the JSON array:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
[{"alias":"daughter","username":"12345","password":"..."},{"alias":"son","username":"67890","password":"..."}]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Using a config file with `uvx`
|
|
133
|
+
|
|
134
|
+
If you prefer a file over inline JSON:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"mcpServers": {
|
|
139
|
+
"librus": {
|
|
140
|
+
"command": "uvx",
|
|
141
|
+
"args": ["librus-mcp"],
|
|
142
|
+
"env": {
|
|
143
|
+
"LIBRUS_CONFIG": "/Users/you/.config/librus/secrets.json"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Alternative: Install from source
|
|
151
|
+
|
|
152
|
+
If you prefer to run from a local clone:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
git clone https://github.com/krzysztoofbury/librus-mcp.git
|
|
156
|
+
cd librus-mcp
|
|
157
|
+
uv venv && uv pip install -e .
|
|
158
|
+
cp secrets.json.template secrets.json # Then fill in credentials
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Then use the full path in your MCP config:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"mcpServers": {
|
|
166
|
+
"librus": {
|
|
167
|
+
"command": "/path/to/librus-mcp/.venv/bin/librus-mcp"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Available Tools
|
|
174
|
+
|
|
175
|
+
| Tool | Description |
|
|
176
|
+
|------|-------------|
|
|
177
|
+
| `list_students()` | List configured student aliases |
|
|
178
|
+
| `get_grades(student_alias)` | Get grades for a student |
|
|
179
|
+
| `get_messages(student_alias)` | Get received messages |
|
|
180
|
+
| `get_message_content(student_alias, message_id)` | Get the body of a specific message |
|
|
181
|
+
| `get_attendance(student_alias)` | Get attendance records |
|
|
182
|
+
| `get_homework(student_alias)` | Get homework for the next 2 weeks |
|
|
183
|
+
| `get_schedule(student_alias, year, month)` | Get calendar events/exams for a month |
|
|
184
|
+
| `get_timetable(student_alias)` | Get current week's timetable |
|
|
185
|
+
| `get_announcements(student_alias)` | Get school announcements |
|
|
186
|
+
|
|
187
|
+
## Project Structure
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
src/
|
|
191
|
+
server.py # MCP server with tool definitions and entry point
|
|
192
|
+
librus_client.py # Librus API client wrapper with caching and retry
|
|
193
|
+
config.py # Configuration loader (reads secrets.json)
|
|
194
|
+
patches.py # Runtime patches for librus-apix bugs
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Contributing
|
|
198
|
+
|
|
199
|
+
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
200
|
+
|
|
201
|
+
## Security
|
|
202
|
+
|
|
203
|
+
To report vulnerabilities, see [SECURITY.md](SECURITY.md).
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|