lasuite-docs-mcp
The lasuite-docs-mcp server provides an MCP interface to the LaSuite Docs external API, enabling comprehensive document management through a secure OpenID Connect (PKCE) authentication flow.
User
Retrieve the authenticated user's profile.
Document Reading
List all accessible documents (with pagination), child documents, document versions, trashbin contents, and favorited documents.
Get a document's metadata or body content (as markdown, HTML, or JSON).
Document Writing
Create documents with an optional title, markdown body, and parent (for nesting).
Update a document's title or content (via raw base64-encoded Yjs data).
Soft-delete documents (move to trashbin) and restore them.
Move documents under a different parent.
Favorites
Add or remove documents from favorites.
Access Control (requires enabling document_access actions in server config)
List, retrieve, create, update, and delete document access permissions for sharing.
Authentication
Uses OIDC Authorization Code + PKCE flow, with refresh tokens stored securely in the OS keychain.
Integration with Auth0 as an OpenID Connect provider for authentication to the LaSuite Docs API.
Integration with Authentik as an OpenID Connect provider for authentication to the LaSuite Docs API.
Integration with Keycloak as an OpenID Connect provider for authentication to the LaSuite Docs API.
Integration with Okta as an OpenID Connect provider for authentication to the LaSuite Docs API.
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., "@lasuite-docs-mcplist my documents"
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.
lasuite-docs-mcp
MCP server for the LaSuite Docs external API.
It exposes Docs operations (list/read/create/update/delete documents, versions,
favorites, current user) as MCP tools. Authentication uses the OIDC
Authorization Code + PKCE flow against any OpenID Connect provider, with a
refresh token cached in the OS keychain. Runs over stdio — no public hosting,
no inbound ports. The OIDC redirect is captured by a one-shot loopback server on
127.0.0.1.
Claude ──stdio──> lasuite-docs-mcp ──Bearer token──> Docs /external_api/v1.0
│
└── Auth Code + PKCE ──> OIDC provider (issues + introspects tokens)Works with any standards-compliant OIDC provider (Keycloak, Authentik, Zitadel, Auth0, Okta, Ory Hydra, …). Authentik is used as a worked example throughout, marked Example (Authentik).
1. Prerequisites
Python ≥ 3.10
A running LaSuite Docs instance with the resource server enabled (§2)
An OIDC provider you control, able to register clients and run token introspection (§3)
Related MCP server: google-workspace-mcp-server
2. Configure LaSuite Docs (server side)
Docs must run as an OIDC resource server. Set in Docs' environment:
OIDC_RESOURCE_SERVER_ENABLED=True
OIDC_OP_URL=<issuer URL of your OIDC provider>
OIDC_OP_INTROSPECTION_ENDPOINT=<provider token-introspection endpoint>
OIDC_RS_CLIENT_ID=<client id Docs uses to call introspection>
OIDC_RS_CLIENT_SECRET=<that client's secret>
OIDC_RS_AUDIENCE_CLAIM=<claim Docs checks for audience, e.g. aud>
OIDC_RS_ALLOWED_AUDIENCES=<value the MCP token must carry, see §3.4>Introspection-response format — important. django-lasuite ships two resource server backends:
| Expects the introspection response as |
| a signed+encrypted JWT (RFC 9701 |
| plain JSON (RFC 7662, standard) |
Most providers (Keycloak, Authentik, Zitadel, Auth0, …) return plain JSON. If yours does, set:
OIDC_RS_BACKEND_CLASS=lasuite.oidc_resource_server.backend.ResourceServerBackendLeave the default only if your provider actually issues JWT-secured introspection
responses (e.g. ProConnect). Wrong choice → 400 Bad Request / "improperly
configured" (see §9).
2.1 EXTERNAL_API action allowlist
EXTERNAL_API controls which resources/actions the resource-server API exposes.
Every tool maps to an action that must appear in this allowlist, or the call
returns 403 (and unknown nested resources return 404). The default only
allows documents: [list, retrieve, create, children] and users: [get_me],
so most tools need it widened. Full config covering every tool in this server:
EXTERNAL_API={"documents":{"enabled":True,"actions":["list","retrieve","create","children","formatted_content","content_retrieve","content","partial_update","destroy","move","favorite","versions_list","trashbin","favorite_list","restore"]},"document_access":{"enabled":True,"actions":["list","retrieve","create","update","partial_update","destroy"]},"users":{"enabled":True,"actions":["get_me"]}}Gotcha — Python literal, not JSON. Docs parses this env var with
ast.literal_eval, so booleans must beTrue/False(capitalized), not JSONtrue/false. JSON booleans crash Docs at boot withValueError: Cannot interpret dict value ... malformed node or string(§9).
Action → tool mapping (non-obvious ones): formatted_content →
get_document_content (reads the body), content → update_document_content
(PATCH raw Yjs), content_retrieve → raw base64 Yjs GET, children →
parented create_document, document_access.* → the *_document_access tools.
2.2 Markdown upload (content on create)
The document resource has no plain content field. create_document with a
markdown body uploads it as a .md file that Docs converts to Yjs server-side.
That conversion needs:
CONVERSION_UPLOAD_ENABLED=TrueWithout it, create_document(markdown=...) returns 400 file upload is not allowed. Reading the body back uses the formatted_content action (above).
Docs validates every token by introspecting it and checking: the token is
active, its issuer equalsOIDC_OP_URL, and its audience claim is inOIDC_RS_ALLOWED_AUDIENCES. All three must line up (§3). Mismatch → 400/401.
3. Configure the OIDC provider
Register a client for the MCP server and make sure the tokens it issues pass Docs' three checks. The concepts are provider-agnostic; the example shows where each lives in Authentik.
3.1 Register the MCP client
Create an OAuth2 / OIDC client for the MCP server:
Client type: public (PKCE, no secret) — recommended for a desktop/CLI tool. Confidential (with secret) also works.
Grant type: Authorization Code (+ refresh token).
Redirect URI:
http://127.0.0.1:8765/callback(exact match; change both here andOIDC_REDIRECT_URItogether).Scopes:
openid profile email(+ an audience scope, §3.4).
Example (Authentik) — Admin → Applications → Providers → Create → OAuth2/OpenID Provider. Set redirect URI
http://127.0.0.1:8765/callback, client type Public, attach an Application. Note its issuer URLhttps://<host>/application/o/<app-slug>/.
3.2 Issuer must match Docs (iss check)
The token's iss claim must equal Docs' OIDC_OP_URL exactly. Easiest way:
let the MCP client and Docs trust the same issuer.
If your provider has one global issuer (Keycloak realm, Zitadel, Auth0 tenant), this is automatic — point both at it.
If your provider issues a per-client/per-application issuer, either reuse the same provider/issuer Docs already trusts, or switch to a global/shared issuer mode so both emit the same
iss.
Example (Authentik) — issuer is per-application by default (
…/o/<slug>/), so a separate MCP application gets a differentissthan the Docs login app →InvalidClaimError: iss. Fix: set the provider's Issuer mode = "Same identifier (global)" on both providers, or have the MCP use the same provider Docs trusts.
3.3 Introspection must accept the token (active check)
Docs introspects with OIDC_RS_CLIENT_ID/SECRET. Many providers only return
active: true when the introspecting client is allowed to introspect that
token (usually the token-issuing client, or one explicitly granted). If a
different client introspects, you get active: false → "user is not active".
Fix: set Docs' OIDC_RS_CLIENT_ID/SECRET to a client permitted to introspect
the MCP tokens — typically the same client that issues them, or configure
your provider's introspection/audience permissions accordingly.
Example (Authentik) — cross-client introspection returns
active:false. Set DocsOIDC_RS_CLIENT_ID/SECRETto the MCP application's client.
3.4 Audience (OIDC_RS_ALLOWED_AUDIENCES check)
The token must carry an audience value that Docs allows. Two approaches:
A — provider emits the audience claim (recommended).
Add a claim/mapper so issued tokens include the configured audience under the
claim Docs reads (OIDC_RS_AUDIENCE_CLAIM). Set
OIDC_RS_ALLOWED_AUDIENCES to that value.
Example (Authentik) — Customisation → Property Mappings → Create → Scope Mapping: scope name
docs, expressionreturn {"docs-aud": "<your-audience>"}. Attach scopedocsto the provider, adddocstoOIDC_SCOPE, set DocsOIDC_RS_AUDIENCE_CLAIM=docs-audandOIDC_RS_ALLOWED_AUDIENCES=<your-audience>. Simpler alternative: use the standardaudclaim (= client id by default) — setOIDC_RS_AUDIENCE_CLAIM=aud,OIDC_RS_ALLOWED_AUDIENCES=<mcp-client-id>.
B — audience request parameter.
If your provider honors an audience auth-request param, set OIDC_AUDIENCE
(§4). Not all providers honor it (Authentik ignores it) — prefer A.
The claim name in OIDC_RS_AUDIENCE_CLAIM and the value in
OIDC_RS_ALLOWED_AUDIENCES must point at the same thing, and that thing must
be present in the token / introspection response.
4. Configure the MCP server
cp .env.example .env # then edit, or pass these via the MCP env block (§6)Var | Meaning |
| Docs host, e.g. |
| API prefix, default |
| Your provider's issuer URL (server reads |
| the MCP client's id |
| empty for public/PKCE; set for a confidential client |
|
|
|
|
| only for §3.4 B; else leave empty |
5. Install
Pick one. All expose the lasuite-docs-mcp command.
uv tool (recommended):
uv tool install git+https://github.com/Bone2510/lasuite-docs-mcp # from GitHub
uv tool install . # local checkoutpipx:
pipx install git+https://github.com/Bone2510/lasuite-docs-mcpEditable dev install:
python -m venv .venv && source .venv/bin/activate
pip install -e .No install (uvx, run on demand):
uvx --from git+https://github.com/Bone2510/lasuite-docs-mcp lasuite-docs-mcp6. Register in Claude Code
Add to your MCP config (~/.claude.json / project .mcp.json). With uv tool/pipx
the command is on your PATH. The installed command runs from an arbitrary working
dir, so pass config via the env block (a .env is only picked up when the cwd
is the project dir):
{
"mcpServers": {
"lasuite-docs": {
"command": "lasuite-docs-mcp",
"env": {
"DOCS_BASE_URL": "https://docs.example.org",
"OIDC_OP_URL": "https://auth.example.org/realms/main",
"OIDC_CLIENT_ID": "lasuite-docs-mcp",
"OIDC_CLIENT_SECRET": "...",
"OIDC_SCOPE": "openid profile email docs",
"OIDC_REDIRECT_URI": "http://127.0.0.1:8765/callback"
}
}
}
}No-install variant:
"command": "uvx",
"args": ["--from", "git+https://github.com/Bone2510/lasuite-docs-mcp", "lasuite-docs-mcp"]On the first tool call the server opens your browser to the provider. After
login it captures the redirect on 127.0.0.1:8765, stores the refresh token in
your OS keychain, and reuses/refreshes it silently afterward.
7. Test standalone
mcp dev lasuite_mcp/server.py # MCP inspector (interactive)Call get_current_user first — it exercises the whole chain (login →
introspection → issuer → audience → user).
8. Available tools
Read: get_current_user, list_documents, get_document (metadata only),
get_document_content (body as markdown/html/json), get_children,
list_versions, list_trashbin, list_favorites.
Write: create_document (optional markdown body), update_document (title),
update_document_content (raw base64 Yjs), delete_document,
restore_document, move_document, add_favorite, remove_favorite.
Accesses (sharing): list_document_accesses, get_document_access,
create_document_access, update_document_access, delete_document_access.
get_documentnever returns the body — Docs stores it as collaborative Yjs. Useget_document_contentto read it (needs theformatted_contentaction, §2.1).
9. Troubleshooting
Server-side errors surface as a bare Django page; the real reason is in the Docs backend logs. Common cases (all server-side OIDC config):
Symptom | Cause / fix |
| RS backend failed to init — |
| Provider returns plain-JSON introspection but |
| Introspecting client may not introspect this token → set Docs RS creds to the token-issuing client (§3.3). |
| Token |
| Token audience ∉ |
Browser never opens | stdio has no TTY; the auth URL is printed to stderr — open it manually. |
| Provider redirect URI ≠ |
| Your Docs version uses a different path — adjust in |
accesses/invitations | Those scopes are disabled in Docs |
| The action is not in the |
| By design — body is Yjs, use |
|
|
Docs crashes at boot, |
|
Port 8765 in use | Change |
10. Security notes
PKCE (S256) is always used, even with a client secret.
Redirect is loopback-only (
127.0.0.1), randomstatechecked against CSRF.Refresh token lives in the OS keychain (via
keyring); if keyring is unavailable it falls back to in-memory (re-login each start).Tokens are never logged.
Notes / unknowns to verify against your instance
Content model (verified against current Docs): the body is a Yjs/BlockNote CRDT, not a field on the document resource. Read it via
get_document_content(formatted-contentendpoint → markdown/html/json). Write paths:create_documentuploads a markdown file that Docs converts to Yjs (needsCONVERSION_UPLOAD_ENABLED);update_document_contentPATCHes a raw base64 Yjs blob (no markdown→Yjs path exists for updates).update_documentonly changes the title.Exact sub-paths (
favorite-list/,move/,restore/,favorite/,accesses/) follow current conventions — confirm against your DocsEXTERNAL_APIroutes.
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/Bone2510/lasuite-docs-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server