Lexware Office MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| LEXWARE_OFFICE_API_KEY | Yes | Your Lexware Office API key. Create one at https://app.lexoffice.de/addons/public-api. | |
| LEXWARE_OFFICE_READ_ONLY | No | If set to 'true', blocks all write operations. This is a hard block that wins over ALLOW_WRITES=true. Defaults to 'true' (read-only by default). | true |
| LEXWARE_OFFICE_ALLOW_WRITES | No | Set to 'true' to explicitly allow write operations (POST, PUT, PATCH, DELETE). Defaults to 'false'. | false |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| searchA | Search the curated Lexware Office API catalog by running a JavaScript async arrow function. Use this before execute to discover endpoints, request shapes, response notes, workflows, and domain-specific caveats. Available global: declare const spec: LexwareApiCatalog; Useful starting points:
Sandbox: no network, filesystem, process, fetch, imports, or API key. Return JSON-serializable data; console logs are captured. Examples: async () => Object.entries(spec.info.domainIndex) .filter(([name, domain]) => [name, ...domain.tags].some(value => value.toLowerCase().includes('contact'))) .map(([name, domain]) => ({ name, ...domain })) async () => { const op = spec.paths['/v1/voucherlist']?.get; return { summary: op?.summary, parameters: op?.parameters, notes: op?.notes, examples: op?.examples }; } |
| executeA | Execute a constrained Lexware Office API workflow by running a JavaScript async arrow function. Use search first when you need endpoint/domain guidance; do not guess Lexware paths from memory. The sandbox exposes no API key, filesystem, process, imports, fetch, or arbitrary network access. Available globals: declare const spec: LexwareApiCatalog; declare const lexware: { request<T = unknown>(input: LexwareRequest): Promise<LexwareResponse>; json(input: LexwareRequest): Promise; paginate<T = unknown>(input: LexwareRequest, options?: { maxPages?: number }): Promise<T[]>; requireNumber(row: unknown, fieldPath: string): number; requireMoney(row: unknown, fieldPath: string): number; sumMoney(rows: unknown[], fieldPath: string): number; formatMoney(cents: number, currency?: string): string; }; type LexwareRequest = { method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; path: string; // relative /v1/... only; no absolute URLs or // hosts query?: Record<string, string | number | boolean | Array<string | number | boolean> | null | undefined>; body?: unknown; // JSON by default; string when rawBody=true (UTF-8 encoded, NOT binary-safe) bodyBase64?: string; // raw binary body as base64; the host decodes it outside the sandbox multipart?: MultipartPart[]; // multipart/form-data uploads (e.g. POST /v1/files); host builds FormData contentType?: string; rawBody?: boolean; accept?: string; }; // At most one of body, bodyBase64, or multipart per request. type MultipartPart = { name: string; value?: string; // plain text form field contentBase64?: string; // binary part content as base64; host decodes it contentPath?: string; // absolute file path on the MCP server machine; host reads the file directly — preferred for local files (no base64, no size blowup) filename?: string; // defaults to the contentPath basename contentType?: string; }; // Exactly one of value, contentBase64, or contentPath per part. type LexwareResponse<T = unknown> = { ok: boolean; status: number; statusText: string; data?: T; text?: string; truncated?: boolean; contentType: string; headers: Record<string, string>; errorCategory?: string; retryAfterSeconds?: number; operation?: { operationId: string; method: string; pathTemplate: string; summary: string }; request: { method: string; path: string; query: Record<string, string[]> }; sent?: { bytes: number; sha256?: string; parts?: Array<{ name: string; filename?: string; bytes: number; sha256: string }> }; // echo of uploaded binary payloads for integrity checks }; lexware.request returns all HTTP responses, including non-OK, as LexwareResponse. Check response.ok/status for recovery logic, or use lexware.json(...) / lexware.paginate(...) when you want non-OK or non-JSON responses to throw. This server is read-only by default. POST, PUT, PATCH, and DELETE are blocked unless the server is started with LEXWARE_OFFICE_ALLOW_WRITES=true. Setting LEXWARE_OFFICE_READ_ONLY=true is a hard block that overrides ALLOW_WRITES. Check spec.info.writesEnabled to branch before attempting a write. Example: async () => { const response = await lexware.request({ path: '/v1/contacts', query: { page: 0, size: 5 } }); return { status: response.status, request: response.request, data: response.data }; } File upload example (bookkeeping Beleg). Never inline file bytes in code — pass the file's absolute path via contentPath and the host reads it from disk: async () => { const response = await lexware.request({ method: 'POST', path: '/v1/files', multipart: [ { name: 'file', contentType: 'application/pdf', contentPath: '/absolute/path/to/receipt.pdf' }, { name: 'type', value: 'voucher' }, ], }); return { status: response.status, id: response.data?.id, sent: response.sent }; } |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: search is for discovering API endpoints and workflows, while execute is for making actual API requests. The descriptions explicitly state to use search before execute, eliminating ambiguity.
Both tool names are single lowercase verbs ('search' and 'execute'), following a consistent imperative style. There is no mixing of conventions or confusing patterns.
With only 2 tools, the server is at the low end of what might be considered adequate. However, the design intentionally uses a minimal pair of discovery and execution, which is reasonable for the broad API access it provides.
The search tool exposes the full API catalog, including workflows and domain guides, while execute can perform any documented API operation. Together they cover the complete lifecycle of discovering and interacting with the Lexware Office API, leaving no functional gaps.