KSeF MCP

KSeF MCP

Single-tenant MCP server for Polish KSeF e-invoice workflows, supporting local stdio testing, draft management, and invoice submission with safety gates.

Category
Visit Server

README

KSeF MCP

Single-tenant MCP server for Polish KSeF e-invoice workflows.

The implementation follows docs/main_spec.md. The first usable path is local stdio against KSeF TEST. Production sends remain disabled unless explicitly opted in.

Current Status

The local implementation now includes the TEST-first stdio path, durable draft/write state, mocked KSeF gateway coverage, and remote HTTP/OAuth resource-server plumbing. Automated checks cover:

  • project scaffold;
  • settings and SQLite state;
  • MCP tool registration surface;
  • TEST-readiness gate shape;
  • red-green tests for the initial safety gates;
  • automated stdio MCP subprocess smoke coverage and executable ksef-mcp-stdio-smoke.
  • Dockerfile and SQLite migrations for the initial durable state.
  • executable ksef-mcp-claude-config-preview coverage for a redacted Claude Desktop config block.
  • executable ksef-mcp-manual-smoke-template coverage for redaction-safe manual evidence notes.
  • executable ksef-mcp-manual-smoke-evidence-check coverage for scanning manual notes before sharing or committing them.
  • executable ksef-mcp-local-preflight coverage for strict config, stdio, and first-draft checks.
  • executable ksef-mcp-test-readiness-smoke coverage for the pre-invoice TEST readiness path.
  • executable ksef-mcp-first-draft-dry-run coverage for the no-network first invoice preflight.
  • guarded executable ksef-mcp-test-submit-smoke coverage for optional live TEST submit runs.
  • executable ksef-mcp-remote-preflight coverage for no-network HTTP/OAuth setup checks before a hosted smoke.
  • readiness/completion audit documentation in docs/READINESS_AUDIT.md.
  • MCP ksef://first-use-checklist resource and first-use-setup prompt for TEST-first personal setup inside connected clients.

Manual Claude Desktop stdio and live HTTP OAuth smokes are still pending; use docs/MANUAL_SMOKE_RUNBOOK.md for pass criteria. Live KSeF TEST readiness, guarded TEST submit, invoice download, and UPO download have been verified against the TEST environment.

The ksef2 TEST readiness gateway is implemented behind an injectable client factory and covered with mocked tests. Token auth and certificate/XAdES auth share the same gateway path; TEST certificate mode can use the SDK-generated test certificate when KSEF_CERT_PATH is not set, while configured DEMO/PROD certificate mode currently expects a PKCS#12 .p12/.pfx file. Live KSeF TEST smoke testing was verified with real TEST credentials on 2026-06-08. The ksef-mcp-test-readiness-smoke command runs the same harmless readiness path from a terminal and persists readiness only after successful TEST authentication. Missing required settings, such as KSEF_NIP, are reported as JSON with next steps rather than a traceback.

KSeF invoice listing/download are gateway-backed and covered with mocked SDK tests. ksef_list_invoices supports seller (sales), buyer (purchase), third_subject, and authorized_subject metadata roles. ksef_get_invoice(include_xml=true) returns downloaded FA(3) XML as an explicitly delimited UNTRUSTED_KSEF_INVOICE_XML block. FA(3) validation uses vendored XSD files from the current ksef2 schema package and runs offline with network access disabled in the XML parser.

ksef_download_upo is implemented for the current KSeF API shape: it requires a session_reference plus exactly one selector (ksef_reference_number, invoice_reference_number, or upo_reference_number). UPO XML returned by download or submit flows is also exposed through an explicitly delimited UNTRUSTED_KSEF_UPO_XML block; raw XML fields remain for compatibility.

The invoice draft workflow is now SQLite-backed. ksef_start_invoice_draft, ksef_update_invoice_draft, and ksef_validate_invoice_draft return deterministic missing-field and blocking-error checklists. ksef_prepare_invoice builds and validates FA(3) XML for standard and simplified invoices, final settlement invoices in PLN or confirmed foreign currency, plus advance and standard correction invoices in PLN or confirmed foreign currency and PLN tax-ID zero-value corrections. Draft start fills missing seller/payment defaults from SELLER_PROFILE_PATH when the profile file is present; seed fields supplied by the user take precedence. When an MCP client advertises form elicitation, the start/update draft wrappers can ask once for a bounded set of common primitive starter fields and apply accepted values through the same validated draft patch path. Unsupported clients, declined/cancelled forms, invalid values, and complex nested fields continue through the structured missing_fields response.

ksef_submit_invoice now enforces the server-side write-safety state machine: valid unexpired confirmation token, production opt-in, durable payload-hash ledger idempotency, token consumption, and gateway-backed online session send/UPO retrieval. This path is covered with mocked SDK tests; live KSeF TEST invoice submission has also been verified with the guarded smoke command, followed by TEST invoice and UPO readback through the read tools.

Foreign-currency standard and final settlement invoices require a confirmed exchange-rate basis before prepare. When the currency is not PLN, the draft must include rate, source, effective date, and confirmed basis; the FA(3) builder emits KursWalutyZ and PLN VAT summary amounts.

Standard invoice drafts preserve payment state and split-payment facts. payment.split_payment=true marks P_18A=1; payment.settlement_status="paid" with payment.payment_date emits Zaplacono/DataZaplaty and does not require a payment method or due date; partial and final_partial emit ZnacznikZaplatyCzesciowej plus ZaplataCzesciowa rows. Rich bank-account entries and skonto terms are emitted as RachunekBankowy, RachunekBankowyFaktora, and Skonto. Standard payment methods are cash, card, voucher, check, credit, bank_transfer, mobile, plus the transfer alias for bank_transfer; unsupported values block draft validation. When a standard payment method or concrete due date is not the right source fact, payment.other_method=true plus payment.description emits PlatnoscInna/OpisPlatnosci, and payment.payment_terms can emit FA(3) TerminOpis descriptive deadlines. Confirmed online payment references can use payment.payment_link and payment.ipksef; the link must include a valid matching IPKSeF query parameter before prepare emits LinkDoPlatnosci and IPKSeF.

Domestic consumer/no-identifier buyers are supported by setting buyer.identifier_type="None" and leaving buyer.identifier_value empty. The generated FA(3) XML marks BrakID=1; contradictory no-ID drafts that also provide an identifier value are blocked before prepare.

Seller and buyer party metadata can be carried through draft, source extraction, and prepare. Seller metadata supports seller.gln, correspondence address fields, seller.vat_prefix, seller.eori_number, seller.email, seller.phone, and seller-only seller.taxpayer_status for FA(3) StatusInfoPodatnika; these can also default from SELLER_PROFILE_PATH. Buyer metadata supports separate buyer.identity_country_code for Other identifiers, primary and correspondence address fields, buyer.gln, buyer.eori_number, buyer.customer_number, buyer.buyer_id, buyer.email, and buyer.phone. The MCP validates buyer NIP, EU VAT, Other ID country/length, and no-ID contradictions before prepare.

FA(3) third-party subjects are supported through third_parties. Each entry must include a name, explicit identity choice, and role; optional primary/correspondence addresses, GLN, contacts, customer number, EORI, buyer ID, and share fields are preserved when confirmed. The generated XML emits a Podmiot3 block with the matching Rola, AdresKoresp, and DaneKontaktowe data. Third-party NIP values must match the FA(3) NIP lexical shape; internal identifiers emit IDWew and must use the NIP-00000 pattern; EU VAT IDs must match the FA(3) KodUE/NrVatUE shape; Other IDs require a valid FA(3) country code and a max-50-character NrID; no-ID third parties must leave identifier_value and identity_country_code empty. Custom third-party roles use other_role=true plus role_description; they are mutually exclusive with the predefined role enum. third_parties.*.share_percentage emits FA(3) Udzial only for additional-buyer rows. third_parties.*.contacts is limited to the FA(3) maximum of three contact rows. Authorized subjects are supported through authorized_subject; the generated XML emits PodmiotUpowazniony with role codes for enforcement authority, court bailiff, or tax representative, optional EORI/contact data, primary address GLN, and correspondence address data. The shorthand authorized_subject.email/phone emits one contact row; explicit authorized_subject.contacts entries can emit up to three FA(3) DaneKontaktowe rows in total.

FA(3) attachments are supported through attachment.data_blocks. Each block must include metadata and either one to ten short paragraphs or one or more tables. Table attachments declare column types/names and rows; every row must match the declared columns, and blank numeric cells require an explicit summary. The generated XML emits Zalacznik/BlokDanych/Tabela. ksef_prepare_invoice checks the current KSeF attachment-permission status before issuing a confirmation token for any draft that contains attachment; ksef_check_attachment_permission exposes the same read-only gateway check directly.

Standard invoice drafts support public/relationship markers as explicit user-confirmed fields: buyer.jst_subordinate_unit emits JST, buyer.vat_group_member emits GV, fp_invoice emits FP, and related_party_transaction emits TP. When JST=1 or GV=1 applies to the buyer, the draft must also include the actual Podmiot3 recipient entity with role jst_recipient or vat_group_recipient and a NIP or internal ID, so KSeF can make the invoice available to that unit/member.

Special invoice annotations are explicit draft flags: cash_accounting emits P_16=1, self_billing emits P_17=1, and simplified_procedure emits P_23=1. Confirmed new_transport_supply emits FA(3) NoweSrodkiTransportu with P_22, P_42_5, and one or more NowySrodekTransportu items for land, vessel, or aircraft details. They remain user-confirmed facts; the MCP does not infer that these procedures or new-means-of-transport rules apply.

Simplified invoices use invoice_type="simplified" and emit FA(3) RodzajFaktury=UPR. This is separate from the simplified_procedure annotation flag. For simplified invoices, buyer name/address can be omitted for NIP, EU VAT, or no-ID buyer identity branches. Standard invoices still require buyer name/address, and buyer.identifier_type="Other" still requires buyer.country_code and buyer.address_line_1 so FA(3) can emit the alternate ID country.

Transaction contract/order references are represented with transaction_conditions.contracts.*.{contract_date,contract_number} and transaction_conditions.orders.*.{order_date,order_number}. They emit FA(3) WarunkiTransakcji/Umowy and WarunkiTransakcji/Zamowienia and are separate from advance-invoice order rows. The same block supports confirmed lot_numbers, delivery_terms, contract_exchange_rate plus non-PLN contract_currency, and intermediary_entity. It also supports bounded transport facts under transaction_conditions.transports.*: a standard transport_type or confirmed other_transport_description, a standard cargo_type or confirmed other_cargo_description, optional transport order number, packaging unit, and start/end timestamps. Transport timestamps are validated against the FA(3) TDataCzas range after the same UTC normalization used by the SDK. The same transport object can carry confirmed carrier identity/address and shipment route addresses: carrier_identity, carrier_address, shipping_from, shipping_via.*, and shipping_to.

Common FA(3) body metadata is supported when it is explicitly confirmed: issue_place emits P_1M, warehouse_documents.* emits repeated WZ, additional_descriptions.* emits DodatkowyOpis, and return_of_excise=true emits ZwrotAkcyzy=1. When billing_period_start is present, the existing required sale_date is treated as the billing period end and the XML emits OkresFa instead of the shared supply date P_6.

Line discounts, amount bases, GTU markers, FA(3) procedure markers, and optional line detail metadata are preserved in generated XML. InvoiceLine.discount reduces the emitted line and summary totals. FA(3) invoice rows accept either lines.*.unit_net_price (P_9A) or lines.*.unit_price_gross (P_9B), but not both; source-confirmed explicit net_amount, gross_amount, and vat_amount map to P_11, explicit P_11A, and explicit P_11Vat. Advance/order rows support explicit net_amount, gross_amount, and vat_amount as P_11NettoZ/P_11VatZ; unit_price_gross is accepted as an input basis and converted to the FA(3) net order-row fields because the schema has no gross-unit order-row element. When a source system provides authoritative FA(3) summary buckets, confirmed summary_overrides.* can emit explicit P_13_*, P_14_*, and P_15 values. The MCP requires summary_overrides.total_gross and blocks the draft unless it equals the supplied summary net and VAT buckets; the prepare preview uses the same explicit totals that the XML emits. invoice_type="correction", invoice_type="advance_correction", and invoice_type="final_correction" drafts may use summary_overrides without lines for summary-only corrections where the source provides corrected FA(3) summary totals. InvoiceLine.gtu_code is emitted as GTU, InvoiceLine.procedure is emitted as Procedura or advance-order ProceduraZ, and lines.*.annex_15_marker=true emits P_12_Zal_15 or P_12Z_Zal_15. lines.*.supply_date emits standard-row P_6A only; advance/order rows block it because FA(3) has no order-line supply-date field. Confirmed unique_id, sku, gtin, pkwiu, cn, pkob, and excise_amount emit the matching invoice-row tags and their advance-order Z variants. Confirmed lines.*.currency_exchange_rate emits row-level KursWaluty on non-PLN standard/final/correction invoice rows; PLN invoices and advance/order rows block it. Advance/order rows also block I_42 and I_63, which are valid only for invoice rows.

Margin-procedure invoices are represented by confirmed margin_procedure plus margin-designated lines (lines.*.tax_regime="margin"). Margin lines must not carry vat_rate or vat_treatment; they emit FA(3) P_13_11 and the selected PMarzy branch. The MCP does not calculate the taxable margin from purchase costs; the user/accountant must confirm the values being invoiced.

Taxi flat-rate lines use lines.*.tax_regime="taxi_flat_rate" with vat_rate=4. They emit FA(3) summary buckets P_13_4 and P_14_4; any other rate or vat_treatment is blocked before prepare.

Special Title XII lines use lines.*.tax_regime="special_xii" with vat_rate_xii. They emit FA(3) P_12_XII/P_12Z_XII and summary buckets P_13_5/P_14_5; ordinary vat_rate and vat_treatment are blocked before prepare.

Line VAT treatments can be provided instead of a numeric VAT rate for non-standard cases: zero_domestic, zero_wdt, zero_export, exempt, reverse_charge, out_of_scope_outside_territory, and out_of_scope_article_100. The builder emits the matching FA(3) P_12/P_12Z code and summary bucket. exempt lines require exactly one confirmed vat_exemption.legal_basis_act, vat_exemption.legal_basis_eu_directive, or vat_exemption.legal_basis_other and emit P_19 plus P_19A, P_19B, or P_19C; reverse-charge lines also mark P_18=1. These classifications remain user-confirmed facts, not automatic tax advice. When an accounting export already carries the FA(3) row classification, lines.*.sale_category can preserve the source-confirmed P_12/P_12Z category directly. It must match any supplied vat_rate or vat_treatment and is not used for margin, taxi flat-rate, or special Title XII rows. Use ksef_advise_vat_treatment before setting cross-border VAT fields. It is read-only and returns status="needs_facts" when buyer country/status, goods movement, place-of-supply, VIES, export, or exemption-basis evidence is missing. For cross-border consumer sales it now pushes back for the OSS/IOSS, distance-sale, local-registration, destination VAT-rate, or consumer service place-of-supply facts instead of hard-refusing the case. Any status="suggested" candidate still requires user/accountant confirmation before ksef_update_invoice_draft.

Advance invoices use invoice_type="advance" and support PLN or confirmed foreign currency. Draft lines are emitted as the FA(3) Zamowienie block, while advance_payments are emitted as ZaliczkaCzesciowa; the MCP blocks prepare unless the received advance-payment sum equals the draft gross total. Foreign-currency advance payments also require currency_exchange_rate, emitted as KursWalutyZW. When a source system provides an authoritative order/contract total, optional advance_order_total preserves FA(3) Zamowienie/WartoscZamowienia; it must be greater than zero, is allowed only on advance or advance-correction invoices with order rows, is blocked for rowless summary corrections, and does not change preview totals or P_15Z.

Final settlement invoices use invoice_type="final" and support PLN or confirmed foreign currency. Draft lines are emitted as normal FaWiersz rows, while advance_invoice_references are emitted as FakturaZaliczkowa; optional deduction amounts/reasons on those references are emitted in Rozliczenie/Odliczenia.

Generic FA(3) settlement adjustments are supported on standard, simplified, advance, correction, tax-ID zero-value correction, advance-correction, final, and final-correction invoices through settlement.charges and settlement.deductions, emitted as Rozliczenie/Obciazenia and Rozliczenie/Odliczenia with computed totals and DoZaplaty or DoRozliczenia. Optional explicit settlement.amount_due or settlement.amount_to_settle is accepted only when it matches the computed balance.

FA(3) footer data is supported through footer.additional_informations and footer.registries. Footer text emits Stopka/Informacje/StopkaFaktury; registry rows emit Stopka/Rejestry fields for PelnaNazwa, KRS, REGON, and BDO. The MCP validates KRS, REGON, BDO length, and blocks empty registry rows before prepare.

Correction invoices use invoice_type="correction", invoice_type="advance_correction", invoice_type="final_correction", or invoice_type="tax_id_zero_correction". Standard, advance, final, and tax-ID zero-value corrections support PLN or confirmed foreign currency. Tax-ID zero-value corrections require original positive before_correction rows plus zero-value after rows. Historical party data can be emitted with corrected_seller as Podmiot1K and corrected_buyers as Podmiot2K only when the buyer identifier is unchanged; corrected buyer data requires matching buyer.buyer_id and corrected_buyers.*.buyer_id linkage. Corrected-party address gln values are emitted inside those historical address blocks. tax_id_zero_correction uses corrected-party data to confirm the original wrong tax ID but does not emit Podmiot1K/Podmiot2K. Correction metadata can also include corrected_invoice_period for OkresFaKorygowanej and corrected_invoice_number_override for NrFaKorygowany. Advance and final-settlement corrections support advance_amount_before_correction as P_15ZK; non-PLN advance/final corrections with that amount also require advance_currency_exchange_rate_before_correction, emitted as KursWalutyZK. Representative live KSeF smoke execution with real credentials remains a separate manual slice.

ksef_lookup_exchange_rate is implemented against the official NBP Web API. It returns the rate, table number, effective date, source URL, and lookup mode. For non-publication dates it falls back to the latest NBP table on or before the requested date within a bounded lookback window. The result is advisory and still requires explicit user confirmation before it can be used as a draft exchange-rate basis. ksef_advise_exchange_rate_basis keeps that raw lookup intact and adds an advisory VAT basis selection for non-PLN invoices: sale date or tax-obligation date use the prior business day under VAT Act art. 31a ust. 1, while invoices issued before the tax obligation use the prior business day before invoice issue under art. 31a ust. 2. The helper returns the suggested rate/table evidence and draft-ready confirmed_basis text, but it never mutates or auto-confirms a draft.

ksef_lookup_counterparty is implemented for Polish domestic NIP and REGON lookups against the official MF VAT whitelist API. It returns candidate legal/VAT data, request provenance, and account number metadata as advisory data only; the MCP does not silently copy names or addresses into a draft.

The same tool now supports EU VAT/VIES validation for identifier_type=VatUe through the official European Commission VIES REST endpoint. It accepts either a prefixed value such as IE6388047V or a split country_code plus VAT number, returns a separate eu_vat_verification block, and marks any source-provided name/address as advisory. VIES is a current-state validation source; as_of_date is not a historical VIES query.

identifier_type=KRS is also supported through the official open KRS API from the Portal Rejestrów Sądowych. It returns current KRS register details such as legal name, KRS, NIP, REGON, legal form, status, registration date, and registered address as advisory candidate data.

GUS REGON/BIR enrichment is available through explicit identifier_type=GUS_REGON, GUS_NIP, or GUS_KRS lookups when GUS_REGON_API_KEY is configured. The tool logs in to the official BIR SOAP service, sends the session id only as the required sid header, logs out best-effort, caches parsed search results in SQLite for 24 hours by default, and returns GUS name, NIP, REGON/KRS, legal-form hint, and address as advisory candidate data.

When bank_account is provided, ksef_lookup_counterparty also calls the MF whitelist account check endpoint and returns a separate bank_account_verification block with TAK/NIE, request ID, and source URL. Bank-account verification remains Polish/MF-only.

MF VAT whitelist 200 responses are cached in SQLite for 24 hours by default (MF_VAT_CACHE_TTL_SECONDS=86400) using separate cache entries for the subject lookup and optional bank-account check.

Source-document support is implemented with SQLite FTS plus optional local vector retrieval. ksef_add_source_document stores untrusted source text and, when KNOWLEDGE_MODE=vector|hybrid and LOCAL_LLM_BASE_URL points at an OpenAI-compatible local embedding endpoint, stores a durable source-document embedding. ksef_search_source_documents supports search_mode=fts|vector|hybrid; all results are advisory snippets. ksef_extract_invoice_source can call a configured local OpenAI-compatible chat model (LOCAL_LLM_BASE_URL + LOCAL_LLM_MODEL) to propose source-backed invoice fields, but it is read-only and does not mutate drafts. ksef_attach_field_provenance links a suggested draft field to a source document only for supported invoice field paths while marking that field unconfirmed until the user explicitly confirms it. Draft confirmations only apply to existing supported advisory fields, so arbitrary keys cannot create or clear confirmation state. ksef_start_invoice_draft(source_document_ids=[...]) can store existing source documents as draft context; missing ids are returned as warnings and no field values are extracted or confirmed automatically. See docs/LOCAL_KNOWLEDGE.md for the current laptop profile guidance: 16 GB starts with FTS, while 32 GB can add hybrid retrieval and a small local extractor/advisor.

ksef_get_capabilities and the ksef://capabilities resource expose the deterministic supported, advisory, unsupported, and manual-smoke workflow surface. Clients should use it before rare FA(3), attachment, correction, cross-border, or non-standard tax paths so the MCP can refuse unsupported cases instead of generating partial XML. The capability surface also lists current MCP resources, including ksef://first-use-checklist, and the terminal preflight commands used before manual external gates.

MCP resources and prompts are registered for client guidance: FA(3) schema, glossary, invoice field checklist, capabilities, sanitized seller profile, knowledge-source catalog, first-use checklist, and guided prompts for first-use setup, issuing an invoice, monthly review, VAT treatment explanation, and source extraction.

Remote Streamable HTTP transport is available behind explicit OAuth resource-server settings. MCP_TRANSPORT=http binds the configured MCP_HTTP_HOST/MCP_HTTP_PORT and refuses startup unless MCP_PUBLIC_URL, OAUTH_ISSUER, OAUTH_AUDIENCE, and OAUTH_JWKS_URL are set. HTTP bearer tokens are validated against the configured JWKS with issuer/audience checks and must include the configured scope, OAUTH_REQUIRED_SCOPES=ksef.mcp by default. Public remote URLs must be HTTPS. Stdio remains the default personal/local path. Run ksef-mcp-remote-preflight before a hosted smoke to check HTTP/OAuth settings without starting the server, using network, writing files, or touching KSeF; live remote deployment smoke and provider-specific onboarding notes are covered in docs/REMOTE_DEPLOYMENT.md, while live HTTP OAuth smoke remains a manual external gate.

See docs/IMPLEMENTATION_PLAN.md, TODO.md, docs/READINESS_AUDIT.md, and docs/MANUAL_SMOKE_RUNBOOK.md.

Local Development

UV_CACHE_DIR=/tmp/uv-cache uv sync --extra dev
UV_CACHE_DIR=/tmp/uv-cache uv run pytest

Run the stdio MCP server:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp

Create your local seller defaults before the first real draft if you want the MCP to fill seller and payment fields automatically:

cp seller_profile.example.yaml seller_profile.yaml

Then edit seller_profile.yaml; it is ignored by git because it contains personal/company data.

Check local configuration before starting the MCP. This validates required env, placeholder NIPs, NIP checksums, auth material, real-NIP TEST acknowledgment, seller-profile placeholders, and seller_profile.yaml seller NIP consistency with KSEF_NIP without network access:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-config-check

To run the local first-use preflight in one command, use:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-local-preflight \
  --seed docs/examples/first_standard_invoice_seed.example.json

This command performs strict config check, stdio MCP handshake, and first-draft dry-run. It does not use the KSeF network and does not submit invoices; its JSON output reports network_used=false, ksef_touched=false, live_submit_attempted=false, and configured_ledger_may_be_touched_by_stdio=true because the stdio server may initialize the configured SQLite ledger.

Before editing a desktop client's MCP config, you can run the same stdio handshake path from a terminal. It starts the server as a subprocess, initializes an MCP client session, lists tools/resources/prompts, calls ksef_session_status, and prints JSON:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-stdio-smoke

For Claude Desktop, use the stdio setup guide in docs/CLAUDE_DESKTOP.md. Generate the redacted config block with:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-claude-config-preview

The preview does not write files, call KSeF, or include KSeF tokens/NIPs in the config JSON; it reports secrets_included=false, writes_files=false, and network_used=false.

Before running manual/external gates, generate a local evidence template. The command prints to stdout and does not write files, load settings, or call KSeF; redirect it to data/ if you want a private ignored notes file:

mkdir -p data
UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-manual-smoke-template --format markdown \
  > data/manual_smoke_evidence.md

Before sharing or committing manual notes, scan them for high-risk unredacted patterns:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-manual-smoke-evidence-check \
  --path data/manual_smoke_evidence.md

Before preparing your first invoice for a configured TEST NIP, you can run the same harmless readiness path outside the chat client:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-test-readiness-smoke

Before creating a real draft in your MCP client, validate the first-draft shape locally. This uses seller_profile.yaml, validates the seed, writes only a temporary SQLite file, and prints real_ledger_touched=false, network_used=false, ksef_touched=false, generated_xml=false, and confirmation_token_created=false:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-first-draft-dry-run \
  --seed docs/examples/first_standard_invoice_seed.example.json

The dry-run can pass without KSEF_TOKEN; the TEST readiness smoke still needs the configured KSeF auth material before any prepare/submit flow.

For an optional end-to-end TEST send outside the chat client, use the guarded live submit smoke. This command requires persisted TEST readiness, uses the configured SQLite ledger, creates a draft and confirmation token, and submits the seed to KSeF TEST only when --confirm-submit-to-ksef-test is present:

UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-test-submit-smoke \
  --seed docs/examples/first_standard_invoice_seed.example.json \
  --confirm-submit-to-ksef-test

If KSEF_TEST_NIP equals KSEF_NIP, also pass --use-real-nip-ack or keep KSEF_ALLOW_REAL_NIP_IN_TEST=true. The JSON output reports readiness_ok, draft_created, confirmation_token_created, confirmation_token_consumed, submitted, gateway_called, and idempotent_replay.

After the dry-run and readiness pass, a minimal standard-invoice seed is available at docs/examples/first_standard_invoice_seed.example.json. Use it as the seed argument to ksef_start_invoice_draft; it assumes seller_profile.yaml already supplies seller and payment defaults.

Inside an MCP client, read ksef://first-use-checklist or run the first-use-setup prompt for the same TEST-first sequence, source-data pushback rules, and prepare/submit gating reminders.

First call:

{
  "seed": {
    "...": "contents of docs/examples/first_standard_invoice_seed.example.json"
  }
}

If the response has missing_fields, each value is a field path to provide before prepare. Patch the returned draft and validate again:

{
  "draft_id": "returned-draft-id",
  "patch": {
    "buyer": {
      "name": "Corrected buyer name"
    }
  }
}

Then call ksef_validate_invoice_draft with {"draft_id": "returned-draft-id"}. Only call ksef_prepare_invoice when ready_for_prepare=true, missing_fields=[], and blocking_errors=[].

If KSEF_TEST_NIP intentionally equals your real KSEF_NIP, prefer a synthetic TEST identifier where possible. Otherwise rerun with --use-real-nip-ack or set KSEF_ALLOW_REAL_NIP_IN_TEST=true after accepting that official TEST data is not isolated.

Use certificate/XAdES mode by setting KSEF_AUTH_MODE=certificate. In TEST, omitting KSEF_CERT_PATH uses the SDK-generated test certificate for the configured KSEF_TEST_NIP. For DEMO/PROD, set KSEF_CERT_PATH to a PKCS#12 .p12/.pfx file and KSEF_CERT_PASSWORD when the archive is encrypted.

Before a remote hosted smoke, validate local HTTP/OAuth settings without starting the server, fetching JWKS, calling OAuth, writing files, or touching KSeF:

MCP_TRANSPORT=http \
MCP_PUBLIC_URL=https://your-mcp.example.com \
OAUTH_ISSUER=https://issuer.example.com/ \
OAUTH_AUDIENCE=https://your-mcp.example.com \
OAUTH_JWKS_URL=https://issuer.example.com/.well-known/jwks.json \
OAUTH_REQUIRED_SCOPES=ksef.mcp \
UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp-remote-preflight

The expected success output includes server_started=false, network_used=false, oauth_network_used=false, ksef_touched=false, writes_files=false, and secrets_included=false.

Run the Streamable HTTP server with external OAuth/JWKS verification:

MCP_TRANSPORT=http \
MCP_PUBLIC_URL=https://your-mcp.example.com \
OAUTH_ISSUER=https://issuer.example.com/ \
OAUTH_AUDIENCE=https://your-mcp.example.com \
OAUTH_JWKS_URL=https://issuer.example.com/.well-known/jwks.json \
OAUTH_REQUIRED_SCOPES=ksef.mcp \
UV_CACHE_DIR=/tmp/uv-cache uv run ksef-mcp

Run the containerized Streamable HTTP service:

cp .env.example .env
# Fill KSEF_* and OAuth values in .env first.
docker compose up --build ksef-mcp

The compose service mounts ./data for the SQLite ledger/drafts and ./seller_profile.yaml read-only for local seller defaults. Create it from seller_profile.example.yaml before starting compose if you want profile defaults:

cp seller_profile.example.yaml seller_profile.yaml

For ChatGPT Apps, Claude.ai, Cloudflare, Auth0, Clerk, Stytch, WorkOS, OAuth client-registration choices, and live smoke expectations, see docs/REMOTE_DEPLOYMENT.md.

Seller profile defaults can be JSON or a conservative key: value YAML subset. Draft start fills only missing fields:

seller:
  name: Example Sp. z o.o.
  nip: REPLACE_WITH_YOUR_NIP
  country_code: PL
  address_line_1: ul. Przykladowa 1
  address_line_2: 00-001 Warszawa
payment:
  method: transfer
  bank_account: 10101010101010101010101010
  due_days: 14

Safety Defaults

  • KSEF_ENV defaults to test.
  • KSEF_AUTH_MODE defaults to token; certificate mode is explicit.
  • KSEF_REQUIRE_TEST_READY defaults to true.
  • ksef_prepare_invoice must refuse until ksef_test_connection_check passes.
  • Source/RAG/LLM suggestions stay unconfirmed unless confirmed through the explicit confirmations argument; draft patches cannot directly set advisory confirmation state.
  • Direct provenance attachment and confirmation keys are restricted to supported invoice field paths; unsupported paths cannot mutate draft advisory state.
  • KSEF_ENV=prod does not allow production sends unless KSEF_ALLOW_PROD=true.
  • MCP_TRANSPORT=http refuses startup unless OAuth/JWKS resource-server settings are complete.
  • KSeF TEST should use synthetic/test identifiers where possible.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured