🎓 fam-mcp
An MCP server for the FAM student portal.
It reads the portal so an assistant can answer what the portal makes you click for
About
TL;DR: a read-only MCP server that gives an AI assistant access to a student's data on the portal of FAM (Faculdade de Americana): grades, absences, assignments, schedule, exams, inbox, forums, finances and complementary hours. The portal has no API, so the server signs in as the student, reads the pages and hands back clean, typed JSON. It does not write anything back.
Why it exists
The portal does its job, but it was built for a browser and a patient person. There is no API, every screen is a full page rendered on the server that takes seconds to load, and the answer to a simple question is usually spread over several of them. What do I have to deliver this week? means the assignments, the forums, the exam calendar and the finance page.
With this server the assistant opens those pages for me, and I just ask. Some things I use it for:
- "What is due this week?" reads the assignments, exams, forums and invoices in one go
- "Can I still miss class in this course?" checks the absences against the allowed maximum
- "What do I need on the last exam to pass?" reads the averages together with the portal's own grading rules
- "How much of the degree is left?" adds up the transcript
How it works
Every tool is a small module. It asks the portal client for one or more pages, parses the HTML into a typed model, and returns it. The portal client keeps a single session for the whole run: it signs in when the server starts, notices when the portal sends it back to the login page, signs in again once and retries the request. Calls that arrive together share that one login.
What it can do
Student
| Tools | What they do |
|---|---|
get_student_profile |
Who is signed in: name, RA, class, term and masked contact data |
Academics
| Tools | What they do |
|---|---|
list_coursesget_class_scheduleget_gradesget_term_resultsget_absencesget_transcriptget_degree_progressget_exam_calendar |
The courses of a term, with teachers and teaching-plan status What happens on each weekday Scores per evaluation stage: N1, N2 and N3 Averages, grading rules and the absences used so far How many classes can still be missed, month by month The full grade history, semester by semester How much of the degree is done and what comes next When the exams are |
Assignments
| Tools | What they do |
|---|---|
list_activitiesget_activitydownload_activity_materialget_agenda |
Assignments with deadline, status and whether they were delivered One assignment in full: instructions, materials and the delivery Saves an attached file so the assistant can read it Everything with a date in the next days, in one sorted list |
Communication
| Tools | What they do |
|---|---|
get_inboxget_inbox_maillist_forumsget_forumlist_surveys |
Inbox messages, filtered by unread or sender One message in full, with its attachments The course forums and whether they are still open A forum's instructions and replies The institutional surveys and which ones were answered |
Finance and requests
| Tools | What they do |
|---|---|
get_financial_statuslist_requestsget_complementary_hours |
Open invoices, with the bank data to check them against The requests opened at the secretariat Complementary activity hours, by status |
Philosophy
Read-only, always.
It never submits, posts or answers anything on the portal. The only side effect comes from the portal itself: opening a message in the inbox marks it as read.
Questions, not screens.
The tools follow what a student actually asks, not how the portal's menu is organized. One question about what's coming up replaces four pages, and finding out how far along the degree is replaces adding up a transcript by hand.
Private by default.
Personal documents like the CPF and the RG come back hidden, other students' names and registration numbers are removed from forum replies, and the login stays in the environment instead of showing up in any answer.
Failures that explain themselves.
When something goes wrong, the assistant gets a clear answer: what happened, whether trying again makes sense and which tool it was. A portal that is down is told apart from a page that changed its layout, and the technical details stay in the log instead of reaching the assistant.
Gentle with a fragile site.
There is one shared session, renewed only when it expires. A call takes from a few seconds to about twenty, and doing several at once barely helps. The server doesn't hide that, and tells the assistant up front.
Shaped for the assistant.
Dates and numbers always come in the same format, and every id the assistant needs comes from a previous answer. The server also says where to start, so the assistant spends its calls on the answer instead of finding its way around.
What's inside
├── assets/ # the How it works diagram, as an editable Excalidraw file and its SVG
├── src/fam_mcp
│ ├── server.py # the MCP server: instructions, middleware and the login at startup
│ ├── portal.py # the session with the portal: login, re-login, retries, decoding
│ ├── middleware.py # turns every failure into the JSON error
│ ├── errors.py # the error hierarchy, one class per failure
│ ├── constants.py # the error codes and their messages
│ ├── utils.py # parsing helpers: dates, numbers, masking
│ ├── data/ # what the tools return, as dataclasses, one module per area
│ └── tools/ # one file per tool, registered automatically on import
└── pyproject.toml
Technologies
| Technology | Used for | |
|---|---|---|
| Model Context Protocol | The protocol that lets an assistant call the tools | |
| FastMCP | The MCP framework: tool registration, input validation, middleware and the startup lifecycle | |
| Python | The language, with asyncio so calls don't block each other |
|
| httpx | The async HTTP client behind the portal session | |
| Beautiful Soup | Reads the portal's HTML, which is often malformed | |
| uv | Dependencies and running the project |
Roadmap
What's already in place:
- ✅ A portal client that signs in, survives an expired session and shares one login between parallel calls
- ✅ 21 read-only tools across the student's profile, academics, assignments, communication and finances
- ✅ Errors as JSON with a code, a retryable flag and the tool that raised them
- ✅ Masked personal data, and forum replies stripped of other students' identifiers
- ✅ Every tool checked against the live portal, including its error cases
- ✅ Server instructions that tell the assistant where to start
What's not there yet:
- ⬜ Sent mail: the portal counts the messages but never renders them
- ⬜ Paid invoices: the portal seems to keep them behind a separate button the server doesn't use yet
- ⬜ Posted scores and pending requests: their parsers haven't met real data yet
- ⬜ A public release, with installation instructions
References
- Model Context Protocol: the specification the server speaks
- FastMCP: the framework the server is built on
- httpx: the HTTP client
- Beautiful Soup: the HTML parser
- uv: how the project is run
- FAM: the portal this server reads
Disclaimer
This project is unofficial. It is not made by, affiliated with or endorsed by FAM.
License
MIT, in LICENSE.md.
Metadata
Release files for fam-mcp 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fam_mcp-0.5.0.tar.gz | 36.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fam_mcp-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 88.2 kB
Release files / fam_mcp-0.5.0.tar.gz
| Download URL | fam_mcp-0.5.0.tar.gz |
|---|---|
| Size | 36.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
443f35838da40a881294ad069ea657968c964710b71c3dc583686d963f6d3043
|
|
BLAKE2b-256 checksum How to use checksums |
661aa5c3303ce9a2f352e33c07da64008504a43555e96ecbc339df06ec3d5a14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fam_mcp-0.5.0-py3-none-any.whl
| Download URL | fam_mcp-0.5.0-py3-none-any.whl |
|---|---|
| Size | 51.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ec1ef0a91e9e31602e1f347a7feb53c883c83301d3c5f1c73db5578341046fd4
|
|
BLAKE2b-256 checksum How to use checksums |
7ba3346599a3ab950784fea4fd4a632b12fbb8cf8e53b34240dd9788bc9f4e3b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|