diff --git a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs
index 48d0f616..94855e12 100644
--- a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs
+++ b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Application/McpDevelopAppService.cs
@@ -248,7 +248,12 @@ public class McpDevelopAppService(
return Problem(McpErrorCodes.InvalidIdentifier, entityName ?? string.Empty);
}
- var seedFile = CrudEndpointSeedFileDto.Generate(entity, operationTypes, objectType, Clock.Now.ToUniversalTime());
+ // Model listeyi JSON dizisi olarak da gonderebilir (["GetList","Create"]); metne cevrilen dizi
+ // virgullu listeye indirilir.
+ var operations = operationTypes is null
+ ? null
+ : string.Join(',', operationTypes.Split(',').Select(item => item.Trim('[', ']', '"', ' ')));
+ var seedFile = CrudEndpointSeedFileDto.Generate(entity, operations, objectType, Clock.Now.ToUniversalTime());
seedFile.Write(configuration);
await timesheetRecorder.RecordAsync(McpTimesheetTexts.GenerateCrudEndpoints, entity);
@@ -319,6 +324,16 @@ public class McpDevelopAppService(
var previous = wizard.EditFileName is null ? null : (await wizardAppService.GetFile(wizard.EditFileName)).Wizard;
wizard.MenuOrder = previous?.MenuOrder ?? 0;
+ // deploy_wizard dosyayi tamamen degistirir. Duzenlemede WizardCode yazilmamissa kod sessizce
+ // App.Wizard.{Ad}'a duser: girdi kismidir ve deploy ekranin menusunu, yetkilerini ve alanlarini
+ // bosaltirdi. Kodu bilerek degistiren girdi WizardCode'u acikca yazar.
+ if (previous is not null && string.IsNullOrWhiteSpace(wizard.ListFormCode) &&
+ !string.IsNullOrWhiteSpace(previous.ListFormCode) &&
+ !string.Equals(previous.ListFormCode.Trim(), wizard.ResolveListFormCode(), StringComparison.OrdinalIgnoreCase))
+ {
+ return Problem(McpErrorCodes.WizardCodeMissing, wizard.EditFileName!, previous.ListFormCode.Trim());
+ }
+
// Alt form sekmesi ana kayit her degistiginde yeniden sorgulanmaz; MCP yeni baglanti
// acarken yenilemeyi kapali yazar. Var olan baglantida kullanicinin ekrandan verdigi
// deger korunur.
diff --git a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Domain.Shared/McpErrorCodes.cs b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Domain.Shared/McpErrorCodes.cs
index fc610604..00c876b8 100644
--- a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Domain.Shared/McpErrorCodes.cs
+++ b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.Domain.Shared/McpErrorCodes.cs
@@ -34,6 +34,7 @@ public static class McpErrorCodes
public const string DevGuideSearchMatches = Prefix + "DevGuideSearchMatches";
public const string InvalidWizard = Prefix + "InvalidWizard";
public const string InvalidWizardValue = Prefix + "InvalidWizardValue";
+ public const string WizardCodeMissing = Prefix + "WizardCodeMissing";
public const string SeedRowsInvalid = Prefix + "SeedRowsInvalid";
public const string SeedRowsNotAllowed = Prefix + "SeedRowsNotAllowed";
public const string SeedRowsUnknownFields = Prefix + "SeedRowsUnknownFields";
diff --git a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpHttpApiModule.cs b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpHttpApiModule.cs
index 2951be40..ade46bf9 100644
--- a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpHttpApiModule.cs
+++ b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpHttpApiModule.cs
@@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol;
using ModelContextProtocol.AspNetCore;
using ModelContextProtocol.Protocol;
+using ModelContextProtocol.Server;
using Sozsoft.Mcp.Tools;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
@@ -85,6 +86,8 @@ public class McpHttpApiModule : AbpModule
// loglar. Hata sonucu (IsError) olarak donulur; model nedeni okuyup devam eder.
filters.AddCallToolFilter(next => async (requestContext, cancellationToken) =>
{
+ McpToolArgumentNormalizer.Normalize(requestContext.Params, requestContext.MatchedPrimitive as McpServerTool);
+
try
{
return await next(requestContext, cancellationToken);
diff --git a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpToolArgumentNormalizer.cs b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpToolArgumentNormalizer.cs
new file mode 100644
index 00000000..1fba379b
--- /dev/null
+++ b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/McpToolArgumentNormalizer.cs
@@ -0,0 +1,69 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using ModelContextProtocol.Protocol;
+using ModelContextProtocol.Server;
+
+namespace Sozsoft.Mcp;
+
+///
+/// Model metin parametresine tirnaksiz deger (section: 4.2) ya da JSON metni yerine dogrudan
+/// dizi/nesne (filter: ["Status","=","Open"]) gonderebilir. SDK her parametreyi ayri ayri
+/// string olarak bagladigi icin bu deger ("Cannot get the value of a
+/// token type 'Number' / 'StartArray' as a string") ile duser. Deger cagri araca ulasmadan, aracin kendi
+/// semasina bakilarak ham JSON metnine cevrilir — JSON bekleyen parametre ayni metni alir; string icin
+/// ozel converter kullanilmaz, cunku arac semasindaki "type": "string" bilgisini siler.
+///
+internal static class McpToolArgumentNormalizer
+{
+ public static void Normalize(CallToolRequestParams? parameters, McpServerTool? tool)
+ {
+ if (parameters?.Arguments is not { Count: > 0 } arguments
+ || tool is null
+ || !tool.ProtocolTool.InputSchema.TryGetProperty("properties", out var properties)
+ || properties.ValueKind != JsonValueKind.Object)
+ {
+ return;
+ }
+
+ Dictionary? normalized = null;
+
+ foreach (var (name, value) in arguments)
+ {
+ if (value.ValueKind is JsonValueKind.String or JsonValueKind.Null or JsonValueKind.Undefined
+ || !properties.TryGetProperty(name, out var schema)
+ || !IsStringOnly(schema))
+ {
+ continue;
+ }
+
+ normalized ??= new Dictionary(arguments);
+ normalized[name] = JsonSerializer.SerializeToElement(value.GetRawText());
+ }
+
+ if (normalized is not null)
+ {
+ parameters.Arguments = normalized;
+ }
+ }
+
+ // Nullable metin parametresi semada ["string", "null"] olarak gelir; baska tip de kabul eden bir
+ // birlesim tipi donusturulmez, degeri SDK oldugu gibi baglar.
+ private static bool IsStringOnly(JsonElement schema)
+ {
+ if (!schema.TryGetProperty("type", out var type))
+ {
+ return false;
+ }
+
+ return type.ValueKind switch
+ {
+ JsonValueKind.String => type.GetString() == "string",
+ JsonValueKind.Array => type.EnumerateArray()
+ .Select(item => item.GetString())
+ .Where(item => item != "null")
+ .SequenceEqual(["string"]),
+ _ => false
+ };
+ }
+}
diff --git a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/Tools/McpDevelopTools.cs b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/Tools/McpDevelopTools.cs
index 90f5aed5..69439f62 100644
--- a/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/Tools/McpDevelopTools.cs
+++ b/api/modules/Sozsoft.Mcp/Sozsoft.Mcp.HttpApi/Tools/McpDevelopTools.cs
@@ -101,7 +101,7 @@ public sealed class McpDevelopTools(IMcpDevelopAppService developAppService, IMc
public async Task DeployWizardAsync(
[Description("Wizard JSON'u: seed dosyasi bicimi ({\"Wizard\": {...}, \"ListForm\": {...}, \"Fields\": [...]}, get_wizard cikisi gibi) ya da duz wizard cevaplari. ListForm/Fields istege baglidir ve kismi olabilir. Enum alanlari sayi olarak yazilir.")]
string wizard,
- [Description("Guncellemede yerine gecilecek dosyanin adi (list_wizards cikisindaki fileName). Yeni wizard icin bos birak.")]
+ [Description("Guncellemede yerine gecilecek dosyanin adi (list_wizards cikisindaki fileName). Yeni wizard icin bos birak. Guncelleme dosyayi tamamen degistirir: wizard girdisi get_wizard ile okunan dosyanin degistirilmis tam halidir; Wizard bolumu (WizardCode, Menu, Language, Groups) eksiksiz gonderilir.")]
string? replaceFileName = null,
[Description("Demo satirlar: JSON nesne dizisi, anahtarlar ekranin alan adlari ([{\"Name\": \"...\"}]). Guid anahtar, TenantId ve audit alanlarini yazma; sunucu ve migrate doldurur. Yalnizca SeedData true olan liste ekraninda.")]
string? seedRows = null)
diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs
index 351987ed..b4d6d201 100644
--- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs
+++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs
@@ -1776,7 +1776,11 @@ public class ListFormWizardAppService(
$"'{wizardName}' adında bir Wizard zaten var ({duplicateFile}). Farklı bir ad verin ya da mevcut kaydı Wizard Manager üzerinden düzenleyin.");
}
- if (previous?.InsertedRecords?.MenuCodes.Contains(code, StringComparer.OrdinalIgnoreCase) == true)
+ // Migrate bekleyen onceki surumun menusu (Pending.Replaced) de bu wizard'indir: veritabaninda
+ // durur ama yeni deploy onu geri alabilir; aksi halde kodunu degistiren deploy'u geri almak
+ // kendi menusuyle catisir.
+ var owned = (previous?.InsertedRecords ?? new WizardInsertedRecordsDto()).Union(previous?.Pending?.Replaced);
+ if (owned.MenuCodes.Contains(code, StringComparer.OrdinalIgnoreCase))
return;
if (rows.Contains(WizardSeedRowStore.MenuFile, nameof(Menu.Code), code) ||
diff --git a/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs b/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs
index 44a16fdf..21af4334 100644
--- a/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs
+++ b/api/src/Sozsoft.Platform.Domain.Shared/PlatformConsts.cs
@@ -278,7 +278,7 @@ public static class PlatformConsts
public const string AdminNameDefaultValue = "Sedat";
public const string AdminSurNameDefaultValue = "ÖZTÜRK";
public const string AdminEmailDefaultValue = "system@sozsoft.com";
- public const string AdminPasswordDefaultValue = "1q2w3E*";
+ public const string AdminPasswordDefaultValue = "K1r1Ut7Z2o@@";
public const string AdminPhoneNumberDefaultValue = "05449476346";
public const string AdminRocketUsernameDefaultValue = "sedat.ozturk";
public const string AdminWorkHourDefaultValue = "00:00-23:59";