Erweitere Marktmanagement-MCP fuer Durchfuehrungen

This commit is contained in:
gitea_admin committed 2026-09-19 08:51:17 +02:00
1 parent df5a533983
commit 3267a121de
3 files changed
+288

No files matched your search

@@ -0,0 +1,216 @@
# Hermes: Market-Management-MCP-API
Stand: 2026-09-19
Status: Aktive technische Schnittstellendokumentation
## Verbindung
Hermes verwendet den MCP-Endpunkt der DEV-App:
```text
https://erpnaurua.imhochrain.ch/api/market-management-mcp.php
```
Jeder Request ist ein JSON-RPC-2.0-Request über HTTPS. Der Request benötigt:
```http
Authorization: Bearer <MARKET_MCP_TOKEN>
Content-Type: application/json
```
Der Token wird nicht in dieser Dokumentation oder im Repository gespeichert.
## Verbindungsablauf
### 1. Initialisieren
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26"
}
}
```
### 2. Werkzeuge laden
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
```
### 3. Werkzeug aufrufen
```json
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "market_management.list_categories",
"arguments": {}
}
}
```
Das Ergebnis steht bei `tools/call` als JSON im Textinhalt des ersten
`content`-Elements.
## Verfügbare Werkzeuge
### Marktdefinitionen
- `market_management.search_markets`
- optional: `search`, `include_archived`, `limit`
- `market_management.get_market`
- erforderlich: `market_id`
- optional: `include_archived`
- `market_management.create_market`
- erforderlich: `name`, `category_id`
- `market_management.update_market`
- erforderlich: `market_id`
- änderbar: `name`, `category_id`
- `market_management.archive_market`
- erforderlich: `market_id`
- `market_management.reactivate_market`
- erforderlich: `market_id`
### Kategorien
- `market_management.list_categories`
Hermes darf Kategorien lesen und bei einem Markt referenzieren, aber keine
Kategorien anlegen oder ändern.
### Durchführungen
- `market_management.create_occurrence`
- erforderlich: `market_definition_id`
- initialer Status: `open`
- weitere Durchführungsfelder sind optional und werden typisiert validiert
- `market_management.get_occurrence`
- erforderlich: `occurrence_id`
- `market_management.update_occurrence`
- erforderlich: `occurrence_id`
- `market_management.archive_occurrence`
- erforderlich: `occurrence_id`
- `market_management.reactivate_occurrence`
- erforderlich: `occurrence_id`
Unterstützte Statuswerte:
```text
open
waitlist
registered
confirmation_pending
confirmed
cancelled
completed
```
Unterstützte Zahlungsstatuswerte:
```text
unpaid
paid
```
### Durchführungstage
- `market_management.create_day`
- erforderlich: `occurrence_id`, `date`
- `market_management.update_day`
- erforderlich: `day_id`
- `market_management.delete_day`
- erforderlich: `day_id`
Weitere mögliche Tagesfelder sind `stand_start_time`, `stand_end_time`,
`setup_start_time`, `setup_end_time`, `delivery_start_time`,
`delivery_end_time` und `observations`.
### Veranstalter und Kosten
- `market_management.set_organizer`
- erforderlich: `occurrence_id`, `organization_contact_id`,
`contact_person_id`
- `market_management.create_cost_item`
- erforderlich: `occurrence_id`, `cost_type`, `gross_amount`, `tax_status`
- `tax_status`: `tax_free` oder `taxable`
- `market_management.delete_cost_item`
- erforderlich: `cost_item_id`
## Beispiel: Markt anlegen
```json
{
"jsonrpc": "2.0",
"id": 10,
"method": "tools/call",
"params": {
"name": "market_management.create_market",
"arguments": {
"name": "Beispielmarkt Hermes Test",
"category_id": 1
}
}
}
```
## Beispiel: Durchführung mit Tag anlegen
```json
{
"jsonrpc": "2.0",
"id": 11,
"method": "tools/call",
"params": {
"name": "market_management.create_occurrence",
"arguments": {
"market_definition_id": 1,
"status": "open",
"place": "Beispielort",
"registration_deadline": "2026-10-01"
}
}
}
```
```json
{
"jsonrpc": "2.0",
"id": 12,
"method": "tools/call",
"params": {
"name": "market_management.create_day",
"arguments": {
"occurrence_id": 1,
"date": "2026-11-21",
"stand_start_time": "09:00",
"stand_end_time": "18:00"
}
}
}
```
## Fachliche Grenzen
- Hermes erhält keinen direkten Datenbankzugriff.
- Hermes darf keine Kategorien anlegen.
- Umsatz und Artikelmengen werden nicht über MCP geschrieben; sie werden aus
den OTC-Verkäufen abgeleitet.
- Markt und Durchführung werden unabhängig archiviert.
- Alle Schreibvorgänge werden serverseitig validiert.
## Fehler
Bei fehlender oder ungültiger Authentifizierung antwortet der Endpunkt mit
HTTP 401. Ungültige JSON-RPC-Requests oder fachlich ungültige Eingaben werden
als JSON-RPC-Fehlerantwort zurückgegeben.
+9
View File
@@ -46,6 +46,9 @@ function market_management_mcp_tools(): array
['name' => 'market_management.create_day', 'description' => 'Durchführungstag anlegen', 'inputSchema' => ['type' => 'object', 'required' => ['occurrence_id', 'date']]],
['name' => 'market_management.update_day', 'description' => 'Durchführungstag ändern', 'inputSchema' => ['type' => 'object', 'required' => ['day_id']]],
['name' => 'market_management.delete_day', 'description' => 'Durchführungstag entfernen', 'inputSchema' => ['type' => 'object', 'required' => ['day_id']]],
['name' => 'market_management.set_organizer', 'description' => 'Veranstalter einer Durchführung setzen', 'inputSchema' => ['type' => 'object', 'required' => ['occurrence_id', 'organization_contact_id', 'contact_person_id']]],
['name' => 'market_management.create_cost_item', 'description' => 'Kostenposition anlegen', 'inputSchema' => ['type' => 'object', 'required' => ['occurrence_id', 'cost_type', 'gross_amount', 'tax_status']]],
['name' => 'market_management.delete_cost_item', 'description' => 'Kostenposition entfernen', 'inputSchema' => ['type' => 'object', 'required' => ['cost_item_id']]],
];
}
@@ -106,6 +109,12 @@ function market_management_mcp_call(PDO $pdo, string $tool, array $arguments): a
$pdo,
market_management_require_positive_id($arguments['day_id'] ?? null, 'day_id')
),
'market_management.set_organizer' => market_management_set_organizer($pdo, $arguments),
'market_management.create_cost_item' => market_management_create_cost_item($pdo, $arguments),
'market_management.delete_cost_item' => market_management_delete_cost_item(
$pdo,
market_management_require_positive_id($arguments['cost_item_id'] ?? null, 'cost_item_id')
),
default => throw new InvalidArgumentException('Unbekanntes MCP-Tool: ' . $tool),
};
}
+63
View File
@@ -442,3 +442,66 @@ function market_management_delete_day(PDO $pdo, int $dayId): array
}
return $day;
}
function market_management_set_organizer(PDO $pdo, array $input): array
{
$occurrenceId = market_management_require_positive_id($input['occurrence_id'] ?? null, 'occurrence_id');
$organizationId = market_management_require_positive_id($input['organization_contact_id'] ?? null, 'organization_contact_id');
$contactPersonId = market_management_require_positive_id($input['contact_person_id'] ?? null, 'contact_person_id');
$stmt = $pdo->prepare(
'INSERT INTO market_occurrence_organizer (occurrence_id, organization_contact_id, contact_person_id)
VALUES (:occurrence_id, :organization_contact_id, :contact_person_id)
ON CONFLICT (occurrence_id) DO UPDATE
SET organization_contact_id = EXCLUDED.organization_contact_id,
contact_person_id = EXCLUDED.contact_person_id,
updated_at = NOW()
RETURNING *'
);
$stmt->execute([
':occurrence_id' => $occurrenceId,
':organization_contact_id' => $organizationId,
':contact_person_id' => $contactPersonId,
]);
return (array) $stmt->fetch();
}
function market_management_create_cost_item(PDO $pdo, array $input): array
{
$occurrenceId = market_management_require_positive_id($input['occurrence_id'] ?? null, 'occurrence_id');
$costType = trim((string) ($input['cost_type'] ?? ''));
$grossAmount = market_management_optional_number($input, 'gross_amount');
$taxStatus = trim((string) ($input['tax_status'] ?? ''));
$taxRate = market_management_optional_number($input, 'tax_rate') ?? '0.00';
if ($costType === '' || $grossAmount === null || !in_array($taxStatus, ['tax_free', 'taxable'], true)) {
throw new InvalidArgumentException('cost_type, gross_amount und tax_status sind erforderlich.');
}
if (($taxStatus === 'tax_free' && $taxRate !== '0.00') || ($taxStatus === 'taxable' && (float) $taxRate <= 0)) {
throw new InvalidArgumentException('tax_rate passt nicht zu tax_status.');
}
$stmt = $pdo->prepare(
'INSERT INTO market_occurrence_cost_item
(occurrence_id, cost_type, description, gross_amount, tax_status, tax_rate)
VALUES (:occurrence_id, :cost_type, :description, :gross_amount, :tax_status, :tax_rate)
RETURNING *'
);
$stmt->execute([
':occurrence_id' => $occurrenceId,
':cost_type' => $costType,
':description' => market_management_optional_string($input, 'description'),
':gross_amount' => $grossAmount,
':tax_status' => $taxStatus,
':tax_rate' => $taxRate,
]);
return (array) $stmt->fetch();
}
function market_management_delete_cost_item(PDO $pdo, int $costItemId): array
{
$stmt = $pdo->prepare('DELETE FROM market_occurrence_cost_item WHERE id = :id RETURNING id, occurrence_id');
$stmt->execute([':id' => $costItemId]);
$item = $stmt->fetch();
if (!is_array($item)) {
throw new RuntimeException('Kostenposition nicht gefunden.');
}
return $item;
}