taxme-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| TAXME_PROFILE | No | Browser profile directory (holds the session — secret) | ~/.taxme-mcp/profile |
| TAXME_CHROMIUM | No | Chromium executable override | auto-detect |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| taxme_statusA | Check whether the BE-Login/TaxMe session is alive (ok) or an interactive SwissID/AGOV login is needed (login_required). Call this before anything else; it also refreshes the cached session. |
| taxme_loginA | Open a visible window for the SwissID/AGOV login (waits up to 8 min). Only status "ok" means the login went through: the portal is asked afterwards whether anybody is logged in, because the login page is served on the portal's own address and being there proves nothing. A login that was never completed comes back as login_required, and nothing is cached. |
| taxme_account_statementA | Open tax amounts (CHF) per tax year. Amounts are only reported under a year the statement itself puts them under; if none can be, the answer is status "unparsable" rather than an empty list that would read as nothing owed. A page that is not a Kontoauszug at all — a maintenance notice, an error page — is "unparsable" too: an empty list is only reported when the statement itself is on the page. |
| taxme_list_returnsB | Tax returns with status. An empty list is only reported when the case list itself is on the page: a page that is not one — a maintenance notice, an error page — and a list whose rows could not be read are both status "unparsable", because "there is nothing to file" must not be concluded from a page that was never asked the question. |
| taxme_open_returnA | Open a tax return (year) for editing; returns the menu sections. Handles the edit popup tab. Only status "ok" means the return is open: the page is checked against the year that was asked for, so a login page or another case comes back as login_required / not_open / wrong_year instead. |
| taxme_menuA | Left-menu sections of the open return with their status. A page carrying no such menu is no return: that comes back as an error naming where the browser is, not as an empty list of sections. |
| taxme_goto_sectionA | Click a menu section by name (substring) in the open return; returns the fields on that page, cut at 60 like taxme_get_fields and saying so with truncated/total. Landing there is checked: TaxMe refuses to open a section while the form still has errors, and the page it hands back instead comes back as an error naming the section you are really on — not as that section's fields under the name you asked for. Which section that is is decided by the menu entry the breadcrumb names, not by the name appearing somewhere in it, because these names nest both ways round ("Wertschriften" at the front of "Wertschriftenverzeichnis", "Einkünfte" at the end of "Übrige Einkünfte"). A breadcrumb is a path and the page is the end of it, so it is read as a path: the last of its steps that names an entry of this menu, and within that step the longest entry, since a longer name that fits contains every shorter one nested inside it. A page carrying no menu is no return at all — an expired session lands on the login form — and comes back as an error saying so. |
| taxme_get_fieldsA | List interactive fields on the current page (id, type, value, label, context, name for a radio — the group, i.e. the one question, its button belongs to — and locked when the portal has switched the field off; a locked field takes no value). Long forms are cut at limit (default 60) and the reply says how many were left out; taxme_fill still resolves against every field. |
| taxme_snapshotA | Current page breadcrumb/url; set screenshot:true for a PNG path. |
| taxme_fillA | Set fields on the current page. Each value: {target, value}. target = field id OR a label/context substring. value must be text, a number or true/false — text→typed (use whole francs for amounts), radio→option value or label, checkbox→true/false (ja/nein, 1/0 and on/off are understood too). A value that is neither a yes nor a no, an option neither a radio group nor a dropdown has (the reply lists the ones it does), and a field the portal has switched off are all refused rather than guessed at, and every value is read back afterwards and compared with what was asked for — a radio the portal hands back unanswered, and a dropdown it hands back on another option or on none, come back as ok:false, not as set. |
| taxme_clickA | Click a button/link by visible text (e.g. "Neuen Eintrag erfassen", "Speichern", "Nächste Seite", "Vorherige Seite", "Ändern"). An exact label wins; failing that a substring matches, and the reply names the button that was actually pressed. An empty or blank label is refused rather than resolved — an empty substring matches every element on the page, so it would press whichever button comes first. |
| taxme_resultsA | Read the Ergebnisse / Steuerberechnung of the open return. Reaching that section is a precondition, and it is settled the way taxme_goto_section settles it — by the menu entry the breadcrumb names — before a word of the page is read: a portal that refused to open the section comes back as an error naming the page you are really on instead of that page's text. A breadcrumb that names no entry of this menu settles nothing there, though, and where it has settled nothing the page itself has to say the section is open before an amount is read off it: the calculation is only ever read from a line the word HEADS — never from the left-menu entry, which is on every page of the return — and, absent a breadcrumb naming the entry, only when that line IS a heading of the page (a heading tag, a legend, a caption, a title/header panel) rather than a sentence beginning with the same word, since a refusal banner can be written either way round and word order is the portal's phrasing, not evidence about which page is open. A click that landed on a page with no menu at all — an expired session lands on the login form — is reported as no return being open, not as a page carrying no calculation. |
| taxme_submit_returnA | DANGER: final submission (Abschluss → Steuererklärung einreichen). Irreversible. Requires confirm:true; otherwise returns a dry-run of the Abschluss page, naming in would_click the one button a confirmed call would press. Reaching that page is a precondition: if no submit button is there, the call is refused rather than pressing whatever the current page happens to offer. A page that already reports the return as filed (already_submitted) is refused too, confirm:true and all — a confirmation that was on the page beforehand could not prove anything about a second click. A page whose text could not be read at all (page_unreadable) is refused for the same reason one step further back: a read that failed is not a page that said no. In both cases the submit button is named as not_clicked rather than would_click, because nothing would be pressed. And a page carrying no menu at all is no return — an expired session lands on the login form — which is said in those words rather than as the Abschluss page merely not being open. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/sapn95/taxme-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server