Vervollstaendige Marktmanagement-MCP-Abdeckung
This commit is contained in:
1 parent
3267a121de
commit
9bde337506
4 files changed
+348
-18
No files matched your search
@@ -32,13 +32,16 @@ function market_management_mcp_tools(): array
|
||||
{
|
||||
return [
|
||||
['name' => 'market_management.search_markets', 'description' => 'Märkte suchen', 'inputSchema' => ['type' => 'object']],
|
||||
['name' => 'market_management.search_occurrences', 'description' => 'Durchführungen suchen und auflisten', 'inputSchema' => ['type' => 'object']],
|
||||
['name' => 'market_management.get_market', 'description' => 'Markt mit Durchführungen lesen', 'inputSchema' => ['type' => 'object', 'required' => ['market_id']]],
|
||||
['name' => 'market_management.create_market', 'description' => 'Markt mit bestehender Kategorie anlegen', 'inputSchema' => ['type' => 'object', 'required' => ['name', 'category_id']]],
|
||||
['name' => 'market_management.update_market', 'description' => 'Markt ändern', 'inputSchema' => ['type' => 'object', 'required' => ['market_id']]],
|
||||
['name' => 'market_management.archive_market', 'description' => 'Markt archivieren', 'inputSchema' => ['type' => 'object', 'required' => ['market_id']]],
|
||||
['name' => 'market_management.reactivate_market', 'description' => 'Markt reaktivieren', 'inputSchema' => ['type' => 'object', 'required' => ['market_id']]],
|
||||
['name' => 'market_management.list_categories', 'description' => 'Bestehende Kategorien lesen', 'inputSchema' => ['type' => 'object']],
|
||||
['name' => 'market_management.create_occurrence', 'description' => 'Durchführung anlegen', 'inputSchema' => ['type' => 'object', 'required' => ['market_definition_id']]],
|
||||
['name' => 'market_management.list_reference_data', 'description' => 'Kategorien, Kantone und Gemeinden lesen', 'inputSchema' => ['type' => 'object']],
|
||||
['name' => 'market_management.get_overview', 'description' => 'Marktübersicht mit serverseitigen Filtern lesen', 'inputSchema' => ['type' => 'object']],
|
||||
['name' => 'market_management.create_occurrence', 'description' => 'Durchführung mit mindestens einem Tag anlegen', 'inputSchema' => ['type' => 'object', 'required' => ['market_definition_id', 'days']]],
|
||||
['name' => 'market_management.get_occurrence', 'description' => 'Durchführung mit Tagen lesen', 'inputSchema' => ['type' => 'object', 'required' => ['occurrence_id']]],
|
||||
['name' => 'market_management.update_occurrence', 'description' => 'Durchführung ändern', 'inputSchema' => ['type' => 'object', 'required' => ['occurrence_id']]],
|
||||
['name' => 'market_management.archive_occurrence', 'description' => 'Durchführung archivieren', 'inputSchema' => ['type' => 'object', 'required' => ['occurrence_id']]],
|
||||
@@ -47,15 +50,107 @@ function market_management_mcp_tools(): array
|
||||
['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.delete_organizer', 'description' => 'Veranstalter einer Durchführung entfernen', 'inputSchema' => ['type' => 'object', 'required' => ['occurrence_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.update_cost_item', 'description' => 'Kostenposition ändern', 'inputSchema' => ['type' => 'object', 'required' => ['cost_item_id']]],
|
||||
['name' => 'market_management.delete_cost_item', 'description' => 'Kostenposition entfernen', 'inputSchema' => ['type' => 'object', 'required' => ['cost_item_id']]],
|
||||
];
|
||||
}
|
||||
|
||||
function market_management_mcp_is_write_tool(string $tool): bool
|
||||
{
|
||||
return in_array($tool, [
|
||||
'market_management.create_market', 'market_management.update_market',
|
||||
'market_management.archive_market', 'market_management.reactivate_market',
|
||||
'market_management.create_occurrence', 'market_management.update_occurrence',
|
||||
'market_management.archive_occurrence', 'market_management.reactivate_occurrence',
|
||||
'market_management.create_day', 'market_management.update_day', 'market_management.delete_day',
|
||||
'market_management.set_organizer', 'market_management.delete_organizer',
|
||||
'market_management.create_cost_item', 'market_management.update_cost_item',
|
||||
'market_management.delete_cost_item',
|
||||
], true);
|
||||
}
|
||||
|
||||
function market_management_mcp_call_idempotent(PDO $pdo, string $userSubject, string $tool, array $arguments): array
|
||||
{
|
||||
if (!market_management_mcp_is_write_tool($tool)) {
|
||||
return market_management_mcp_call($pdo, $tool, $arguments);
|
||||
}
|
||||
|
||||
$idempotencyKey = trim((string) ($arguments['idempotency_key'] ?? ''));
|
||||
if ($idempotencyKey === '') {
|
||||
throw new InvalidArgumentException('Schreibende MCP-Aufrufe benötigen idempotency_key.');
|
||||
}
|
||||
$clientId = trim((string) ($arguments['client_id'] ?? 'hermes'));
|
||||
if ($clientId === '') {
|
||||
throw new InvalidArgumentException('client_id darf nicht leer sein.');
|
||||
}
|
||||
$businessArguments = $arguments;
|
||||
unset($businessArguments['idempotency_key'], $businessArguments['client_id']);
|
||||
$requestHash = hash('sha256', json_encode([
|
||||
'tool' => $tool,
|
||||
'arguments' => $businessArguments,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
|
||||
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
$existingStmt = $pdo->prepare(
|
||||
'SELECT user_subject, request_hash, result_status, result_payload
|
||||
FROM market_mcp_idempotency
|
||||
WHERE client_id = :client_id AND idempotency_key = :idempotency_key
|
||||
FOR UPDATE'
|
||||
);
|
||||
$existingStmt->execute([':client_id' => $clientId, ':idempotency_key' => $idempotencyKey]);
|
||||
$existing = $existingStmt->fetch();
|
||||
if (is_array($existing)) {
|
||||
if ((string) $existing['user_subject'] !== $userSubject || (string) $existing['request_hash'] !== $requestHash) {
|
||||
throw new InvalidArgumentException('Idempotency-Schlüssel wurde bereits für eine andere Anfrage verwendet.');
|
||||
}
|
||||
if ((string) $existing['result_status'] === 'succeeded' && $existing['result_payload'] !== null) {
|
||||
$pdo->commit();
|
||||
return (array) json_decode((string) $existing['result_payload'], true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
throw new RuntimeException('Idempotency-Anfrage wird bereits verarbeitet oder ist fehlgeschlagen.');
|
||||
}
|
||||
|
||||
$insert = $pdo->prepare(
|
||||
'INSERT INTO market_mcp_idempotency
|
||||
(user_subject, client_id, idempotency_key, tool_name, request_hash, result_status, expires_at)
|
||||
VALUES (:user_subject, :client_id, :idempotency_key, :tool_name, :request_hash, \'processing\', NOW() + INTERVAL \'24 hours\')'
|
||||
);
|
||||
$insert->execute([
|
||||
':user_subject' => $userSubject,
|
||||
':client_id' => $clientId,
|
||||
':idempotency_key' => $idempotencyKey,
|
||||
':tool_name' => $tool,
|
||||
':request_hash' => $requestHash,
|
||||
]);
|
||||
$result = market_management_mcp_call($pdo, $tool, $businessArguments);
|
||||
$update = $pdo->prepare(
|
||||
'UPDATE market_mcp_idempotency
|
||||
SET result_status = \'succeeded\', result_payload = CAST(:result_payload AS JSONB)
|
||||
WHERE client_id = :client_id AND idempotency_key = :idempotency_key'
|
||||
);
|
||||
$update->execute([
|
||||
':result_payload' => json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR),
|
||||
':client_id' => $clientId,
|
||||
':idempotency_key' => $idempotencyKey,
|
||||
]);
|
||||
$pdo->commit();
|
||||
return $result;
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
function market_management_mcp_call(PDO $pdo, string $tool, array $arguments): array
|
||||
{
|
||||
return match ($tool) {
|
||||
'market_management.search_markets' => market_management_search_markets($pdo, $arguments),
|
||||
'market_management.search_occurrences' => market_management_search_occurrences($pdo, $arguments),
|
||||
'market_management.get_market' => market_management_get_market(
|
||||
$pdo,
|
||||
market_management_require_positive_id($arguments['market_id'] ?? null, 'market_id'),
|
||||
@@ -78,6 +173,11 @@ function market_management_mcp_call(PDO $pdo, string $tool, array $arguments): a
|
||||
false
|
||||
),
|
||||
'market_management.list_categories' => market_management_list_categories($pdo),
|
||||
'market_management.list_reference_data' => market_management_list_reference_data($pdo, $arguments),
|
||||
'market_management.get_overview' => [
|
||||
'markets' => market_management_search_markets($pdo, $arguments),
|
||||
'occurrences' => market_management_search_occurrences($pdo, $arguments),
|
||||
],
|
||||
'market_management.create_occurrence' => market_management_create_occurrence($pdo, $arguments),
|
||||
'market_management.get_occurrence' => market_management_get_occurrence(
|
||||
$pdo,
|
||||
@@ -110,7 +210,16 @@ function market_management_mcp_call(PDO $pdo, string $tool, array $arguments): a
|
||||
market_management_require_positive_id($arguments['day_id'] ?? null, 'day_id')
|
||||
),
|
||||
'market_management.set_organizer' => market_management_set_organizer($pdo, $arguments),
|
||||
'market_management.delete_organizer' => market_management_delete_organizer(
|
||||
$pdo,
|
||||
market_management_require_positive_id($arguments['occurrence_id'] ?? null, 'occurrence_id')
|
||||
),
|
||||
'market_management.create_cost_item' => market_management_create_cost_item($pdo, $arguments),
|
||||
'market_management.update_cost_item' => market_management_update_cost_item(
|
||||
$pdo,
|
||||
market_management_require_positive_id($arguments['cost_item_id'] ?? null, 'cost_item_id'),
|
||||
$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')
|
||||
|
||||
Reference in new issue
Block a user