Malt MCP Server
Provides tools to read and write freelance profile data on Malt.fr, including profile info, stats, missions, revenue, availability, and project offers, as well as profile editing (headline, bio, daily rate, skills) and availability status updates.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Malt MCP Serverupdate my daily rate to €500"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Malt MCP Server
MCP server for Malt.fr. Lets Claude (or any MCP client) read your freelance profile, stats, and missions, and update your profile.
This is a fork. It builds on LeoMbm/malt-mcp (Apache-2.0), originally by Leonidas Jeremy, which provides the browser/session foundation and the DOM-scraping read tools. This fork, maintained by JLMael, adds a reverse-engineered layer over Malt's internal REST API (read and write), profile-editing tools, and a documented endpoint map.
A browser is required, there is no headless/API-only mode. Malt sits behind Cloudflare and binds the session to the browser, so even the API calls run as fetch inside an authenticated Chromium page. See How it works.
The upstream PyPI package (malt-mcp) and .mcpb release are the original project's and do not include this fork's API/write additions yet. To use this fork, install it from source.
Tools
Tool | Description | Status |
| Log in to Malt interactively from Claude Desktop | working |
| Get freelance profile info (bio, daily rate, skills, rating). Omit username to fetch your own profile. | working |
| View profile stats (views, response rate, missions) | working |
| List mission conversations from messaging | working |
| Get full details of a specific mission (budget, skills, messages) | working |
| Write: update headline, bio, daily rate, and add/remove/replace skills. Dry run by default, pass | working |
| Visibility stats + weekly/monthly counters + history (API) | working |
| Super Malter scoring breakdown + level thresholds (API) | working |
| Revenue figures + mission summary (API) | working |
| Availability status + search-visibility preferences (API) | working |
| Account identity + profile summary + company (API) | working |
| List client project offers / conversations, paginated (API) | working |
| Write: set availability (AVAILABLE / NOT_AVAILABLE) via API. Dry run by default, pass | working |
| Close the browser and free resources | working |
✍️ Writing to your profile (update_profile)
update_profile is the only tool that modifies your Malt account. It is guarded:
Dry run by default. Without
confirm=true, nothing is written, the tool only returns the validated changes it would apply.Partial updates. Only the fields you pass (
headline,bio,daily_rate, and the skills fields) are touched.Verified writes. After saving, the profile page is re-read and each field is compared against the requested value. The result reports
verified: true/falseper field.
Skills, full CRUD:
skills: skills to add (additive; existing skills are kept).remove_skills: skills to delete (case-insensitive match).replace_skills: true: treatskillsas the exact desired list, the tool adds the missing ones and removes everything else. In this mode, omitremove_skills.
Skill deletion clicks the cross icon on each drawer chip (data-testid$='-icon-remove'), expanding the collapsed list first. Verified end-to-end on a live session. If Malt changes its edition UI, the skills path in malt_mcp_server/scraping/update_profile.py is the first thing to re-check.
Automated profile edits may violate Malt's TOS. This tool changes what clients see on your public profile, review the dry-run output before confirming, and use at your own risk.
📊 API-based read tools
Some read tools skip DOM scraping entirely and call Malt's internal REST API. Malt has no public/GraphQL API, so these run fetch inside the authenticated browser page (page.evaluate): the request inherits the session cookies and passes Cloudflare like any in-app request. This is lighter and more stable than parsing HTML.
Tool | Aggregated endpoints |
|
|
|
|
|
|
|
|
|
|
|
|
Output is structured JSON with Malt's original field names. All API paths live in constants.py; the shared fetch helper is core/api.py. The reverse-engineered endpoint map is in docs/malt-api.md. These tools are read-only and never mutate anything.
get_project_offers(status="ACTIVE", page=0, page_size=20) returns Malt's paginated envelope as-is (content, totalElements, first, last, numberOfElements, empty, pageNumber, pageSize, type). The content items are passed through untouched: their per-item schema is not yet confirmed (the capture had no offers) and will be documented once real offers exist.
✏️ API-based write tools
Writes go through the same internal REST API, using a mutating verb (PUT/POST/PATCH) plus an anti-CSRF header: X-XSRF-TOKEN is read from the XSRF-TOKEN cookie inside the page. The shared helper is api_write(page, method, path, payload) in core/api.py; if the CSRF cookie is missing it fails cleanly without sending anything.
Tool | Endpoint | Effect |
|
| Set AVAILABLE / NOT_AVAILABLE + frequency |
set_availability(available, frequency="FULL_TIME", confirm=false) is dry run by default, exactly like update_profile: without confirm=true it writes nothing and returns {"dry_run": true, "would_send": {...}}. With confirm=true it PUTs the payload, then re-reads the endpoint to verify (Malt reports a fresh confirmation as AVAILABLE_AND_VERIFIED).
Write tools change your live Malt account. Review the dry-run output before confirming, and mind Malt's TOS on automation.
Related MCP server: Upwork MCP Server
📦 Claude Desktop MCP Bundle
Prerequisites: Claude Desktop.
One-click installation:
Download the latest
.mcpbfrom releasesDouble-click the
.mcpbfile to install it into Claude DesktopAsk Claude "connecte-moi a Malt" - a browser opens, you log in, done
Call any Malt tool
No terminal needed. Session is saved in ~/.malt-mcp/ and reused across restarts.
Google OAuth doesn't work (blocked by Google when automated). Use email/password.
🚀 uvx Setup (Universal)
Prerequisites: uv installed.
Add to your MCP client config (Claude Desktop, Claude Code, or any MCP-compatible client):
{
"mcpServers": {
"malt": {
"command": "uvx",
"args": ["malt-mcp@latest"],
"env": { "UV_HTTP_TIMEOUT": "300" }
}
}
}@latest pulls the newest version from PyPI on each launch. First auth-requiring call opens a browser for login.
To log in ahead of time:
uvx malt-mcp@latest --loginDocker (coming soon)
⚙️ CLI Options
Option | Description |
| Open browser to log in and save session |
| Clear stored browser profile |
| Show browser window (debug) |
| Set log level (DEBUG, INFO, WARNING, ERROR) |
| Browser timeout in ms (default: 5000) |
❗ Troubleshooting
Login issues:
Google OAuth won't work. Use email/password.
Session expired? Re-run
uvx malt-mcp@latest --login.Cloudflare challenge on first load is normal - the browser handles it, give it a few seconds.
Timeout issues:
Pages not loading? Try
--timeout 10000. Slow connections might need15000.
Browser issues:
Headless mode doesn't work - Cloudflare blocks it. The browser window is expected.
First run downloads Chromium (~200 MB via Patchright). One-time thing.
Upgrading from v0.3.x? Run
uvx malt-mcp@latest --logoutthen--login. The browser engine changed from system Chrome to managed Chromium.
🔒 How it works
Under the hood, this is browser automation via Patchright (Playwright fork), required because Malt is behind Cloudflare, which rejects plain HTTP clients and headless browsers. Everything runs on one authenticated Chromium session, in two complementary layers:
DOM scraping (from upstream): reads/writes where Malt has no clean API, profile read, stats, missions, and the profile-edition drawers.
Internal REST API (added by this fork): Malt has no public/GraphQL API, so its internal endpoints were reverse-engineered and are called via
fetchinside the authenticated page (page.evaluate). The request inherits the session cookies and passes Cloudflare like any in-app XHR, lighter and more stable than parsing HTML, but still browser-bound. The endpoint map is indocs/malt-api.md.Credentials stay local. Cookies live in
~/.malt-mcp/profile/, nowhere else.Writes are opt-in. Every tool is read-only except
update_profile, which is a dry run unless you explicitly passconfirm=true.Runs locally. The server talks to Malt.fr and nothing else.
Malt's TOS may prohibit automated tools. Don't bulk-scrape. Use responsibly.
🐍 Development
Contributions welcome! See CONTRIBUTING.md for architecture guidelines.
git clone https://github.com/JLMael/Malt-MCP.git
cd Malt-MCP
uv sync --group dev
pre-commit installRun the MCP Inspector (local testing):
uv run mcp dev malt_mcp_server/server.pyRun tests:
uv run pytest --cov -vType check:
uv run ty checkLicense
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/JLMael/Malt-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server