Skip to main content
Glama

Dienstreiseantrag Model Context Protocol (DRA-MCP)

A model context protocol server for filling out business trip application forms.

Note that DRA-MCP is in early stage of development. It may later be used in production and for teaching. Hence, suggestions and improvements are welcome, as long as we don't over-engineer it.

Setup

It is recommended to install uv first.

git clone https://github.com/scads/dra-mcp
cd dra-mcp
uv sync

Put reusable applicant details in .env:

SERVICE_UNIT=
APPLICANT_NAME=
DEPARTMENT=
OFFICE_PHONE=
HOME_ADDRESS=
ADDITIONAL_HOME_ADDRESS=
TEMPORARY_STAY_ADDRESS=
IBAN=
BIC=
BANK_NAME=

This file is ignored by Git because it may contain personal and banking information.

If you use this tool via an MCP-compatible AI-agent such as Jan.AI (open source), it is recommended to use privacy-preserving, local-only Large Language Models. If you use a cloud-service for this, be aware that information such as your home adress and bank account might be shared with this cloud service provider!

Related MCP server: Trip Planner MCP Server

MCP server

business_trip_mcp_server.py exposes create_business_trip_application as an MCP tool via FastMCP, so an MCP-compatible AI agent can fill out and generate the PDF for you. It also ships a business_trip_travel_planning_guide prompt with detailed rules for choosing the transport mode (train vs. flight) and estimating realistic departure/return dates and times, assuming the traveller starts from Leipzig.

Install dependencies and run the server with uv:

uv sync
uv run python business_trip_mcp_server.py

Point your MCP-compatible client (e.g. Jan.AI) at this command (uv run python business_trip_mcp_server.py, working directory dra-mcp) to add it as a stdio MCP server. Most clients (Jan.AI, Claude Desktop, VS Code, ...) accept a JSON config such as:

{
  "mcpServers": {
    "dra": {
      "active": true,
      "args": [
        "--directory",
        "path/to/dra-mcp",
        "run",
        "business_trip_mcp_server.py"
      ],
      "command": "uv"
    }
  }
}

Use via Terminal and Python (without AI agents)

python business_trip.py --help
python business_trip.py `
  --application-kind business-trip `
  --destination "Dresden" `
  --purpose "Project meeting" `
  --departure-date 2026-10-12 `
  --outbound-train `
  --return-train `
  --output completed-trip.pdf

The CLI accepts options for all applicant-editable text fields, choices, and checkboxes. Omitted fields stay blank in the PDF. Boolean options support both --option and --no-option; radio choices are listed by --help.

The same function can be called from Python:

from business_trip import create_business_trip_application

create_business_trip_application(
    "completed-trip.pdf",
    destination="Dresden",
    purpose="Project meeting",
    outbound_train=True,
)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. Note: Large parts of the code in this repository were vibe-coded using GitHub Copilot integration in Visual Studio Code. When modifying code here, consider using a similar tool.

Acknowledgements

We acknowledge the financial support by the Federal Ministry of Research, Technology and Space of Germany and by Sächsische Staatsministerium für Wissenschaft, Kultur und Tourismus in the programme Center of Excellence for AI-research „Center for Scalable Data Analytics and Artificial Intelligence Dresden/Leipzig“, project identification number: ScaDS.AI

Available Tools

1 tool
create_business_trip_applicationCreate Business Trip ApplicationA

You are helping fill out a German business-trip application (Dienstreiseantrag). The applicant is based in Leipzig, Germany. Use the following rules to decide transport mode, checkboxes, and dates before calling create_business_trip_application. Do not make up information! E.g. if you don't know the applicant's home address, IBAN, or other personal details, leave them None or null (not empty string). You must provide these fields, and you need to reason some of them based on what is given by the user:

  • destination (at least postal code + city + country, if not in Germany)

  • purpose (meeting name or similar)

  • departure_date

  • departure_time

  • business_start_date

  • business_start_time

  • business_end_date

  • business_end_time

  • return_date

  • return_time

These fields are optional and not required:

  • service_unit

  • applicant_name

  • department": "Antragsteller.Referat",

  • office_phone

  • home_address

  • additional_home_address

  • temporary_stay_address

  • overnight_cost_per_night

  • private_car_reason (only required if using a private car for traveling)

  • flight_reason (only required if using a flight for traveling)

  • private_stay_from

  • private_stay_until

  • private_stay_destination

  • iban

  • bic

  • bank_name

  • explanations

  • explanations_continuation

  • application_date If the user didn't provide them, do not fill them! Keep them None / null.

Choosing the transport mode

  • Destinations inside Germany, or otherwise reachable comfortably by rail in a few hours (e.g. neighbouring countries such as Poland, Czechia, or nearby parts of Austria/Netherlands), should use train + public transport for both legs: set outbound_train=True, outbound_bus_or_public_transport=True, return_train=True, return_bus_or_public_transport=True.

  • Destinations that are far away, overseas, or would otherwise require a very long train ride (roughly more than half a day of travel each way, e.g. most of Western/Southern Europe onward, or anywhere outside Europe) should use flight instead: set outbound_flight=True and return_flight=True. Use flight_reason / flight_reason_continuation to justify the choice if asked.

  • Only select one primary mode per leg unless additional legs (e.g. bus/public transport to/from the airport or station) are genuinely part of the journey.

Estimating departure and return dates/times

Assume the traveller starts and ends every trip in Leipzig. Before setting departure_date/departure_time and return_date/return_time, estimate the one-way travel time from Leipzig to the destination (and back):

  • Nearby destinations reachable within roughly 2-3 hours (e.g. Dresden, Berlin, Halle): same-day travel is fine; departure can be the morning of business_start_date and return the evening of business_end_date.

  • Mid-distance destinations requiring roughly half a day of travel each way (e.g. Paris, Munich to a far corner of Germany, most of Central Europe by train, or a short flight including airport transfer time): if business_start_time is in the early morning (roughly before 9-10am), the traveller cannot arrive in time same-day, so set departure_date to the day BEFORE business_start_date (with an afternoon/evening departure_time). Otherwise, an early-morning departure on business_start_date itself may be reasonable. Apply the same logic symmetrically to the return: if business_end_time is late in the day and travel home would take half a day, set return_date to the day AFTER business_end_date; only keep the return on the same day if there is clearly enough remaining time after the business ends.

  • Long-distance/overseas destinations reachable only by flight: budget extra time for airport transfers, check-in, and connections. Set the departure the day before the business start whenever the start time plus necessary travel time would not otherwise be reachable, and similarly delay the return by a day when the business end time is late.

  • When in doubt, prefer arriving with a comfortable buffer (e.g. arriving the evening before an early-morning meeting) over risking a missed appointment, but avoid padding travel by more than necessary (don't add a full travel day for a destination that's only 1-2 hours away).

Note that departure_date and departure_time must be reasonably BEFORE business_start_date and business_start_time, and return_date and return_time must be reasonably AFTER business_end_date and business_end_time.

General notes

  • Dates accepted by the tool are YYYY-MM-DD or DD.MM.YYYY; times are free text (e.g. "08:00").

  • Personal fields (home address, IBAN, etc.) fall back to values in .env if not provided; do not invent these values yourself, ask the user if they are missing and not already on file.

  • Leave fields unset (do not guess) when information is genuinely unknown; blank fields stay empty in the generated PDF for the applicant or office to fill in later.

  • When the application was created, provide a markdown link to the file, e.g. .

ParametersJSON Schema
NameRequiredDescriptionDefault
bicNo
ibanNo
purposeYes
bank_nameNo
breakfastNo
departmentNo
destinationYes
return_dateYes
return_timeYes
explanationsNo
home_addressNo
office_phoneNo
return_trainNo
service_unitNo
bahncard_rateNo
flight_reasonNo
meal_providerNo
return_flightNo
travel_end_atNo
applicant_nameNo
bahncard_classNo
departure_dateYes
departure_timeYes
outbound_trainNo
travel_card_toNo
bahncard_numberNo
outbound_flightNo
application_dateNo
application_kindNo
requests_advanceNo
travel_card_fromNo
business_end_dateYes
business_end_timeYes
employment_statusNo
overnight_paymentNo
private_stay_fromNo
travel_start_fromNo
bonus_program_nameNo
overnight_providerNo
overnight_requiredNo
private_car_reasonNo
private_stay_untilNo
return_private_carNo
business_start_dateYes
business_start_timeYes
meals_provided_freeNo
return_official_carNo
bahncard_valid_untilNo
outbound_private_carNo
outbound_official_carNo
has_field_service_roleNo
return_other_transportNo
temporary_stay_addressNo
additional_home_addressNo
additional_participantsNo
uses_official_air_milesNo
outbound_other_transportNo
overnight_cost_per_nightNo
private_stay_destinationNo
explanations_continuationNo
uses_personal_travel_cardNo
flight_reason_continuationNo
participates_in_bonus_programNo
return_bus_or_public_transportNo
private_car_reason_continuationNo
return_other_transport_selectedNo
return_passenger_in_private_carNo
outbound_bus_or_public_transportNo
outbound_other_transport_selectedNo
outbound_passenger_in_private_carNo
requests_flight_cost_reimbursementNo
requests_recognition_for_private_carNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses accepted date/time formats, that missing personal fields fall back to .env rather than being invented, that unknown fields stay null (blank in the PDF), and that the output is a PDF referenced by markdown link. It does not mention auth/permissions or side effects beyond file creation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Given the complexity, the length is largely justified and it is well front-loaded and organized under markdown headers. There is minor waste and a malformed artifact ('department": "Antragsteller.Referat"') that slightly mars an otherwise clean structure.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value documentation is unnecessary, and the description instead covers the required-field contract, transport reasoning, and output-link convention. The main remaining gap is the large set of undocumented optional parameters.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 72 parameters, so the description must compensate. It explains the 10 required fields well (destination format, the transport-mode booleans, and date/time semantics) and lists several optionals, but dozens of parameters (bahncard_*, meal/overnight fields, bonus-program, travel_end_at, employment_status, application_kind) are never described, leaving the agent to infer from names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line states a specific verb and resource: helping create/fill out a German business-trip application (Dienstreiseantrag), with the creation call named explicitly. There are no sibling tools to differentiate from, and the scope (destination, transport, dates) is immediately legible.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives unusually rich context on how to reason before calling: transport-mode selection rules, date/time estimation logic, and the constraint that departure precedes business_start and return follows business_end. It stops short of stating when NOT to use the tool, but no alternatives exist to route against.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.1.0
    • First observedcreate_business_trip_application

TDQS

A4.1/5.0

Scored across 1 tool

Disambiguation5/5

Only one tool exists, so there is no possibility of misselection or overlapping purpose. The tool's purpose is clearly stated and distinct.

Naming Consistency5/5

The single tool uses a clear snake_case verb_noun pattern (create_business_trip_application), consistent with common MCP naming conventions.

Tool Count3/5

A single tool for a complex, specialized task feels thin. While it covers creation, the expected range for a well-scoped server is typically 3–15 tools, so this is borderline.

Completeness3/5

The tool covers creation of a business trip application but lacks read, update, or delete operations. The lifecycle is incomplete for managing applications beyond initial creation.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers