跑通MCP反射通信机制流程
This commit is contained in:
parent
d655680fde
commit
c05f19b313
@ -98,9 +98,11 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="client\" />
|
||||
<Folder Include="resource\" />
|
||||
<Folder Include="server\" />
|
||||
<PackageReference Include="log4net" Version="3.1.0-preview.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-preview.3.25171.5" />
|
||||
<PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.12" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="10.0.0-preview.3.25171.5" />
|
||||
</ItemGroup>
|
||||
<Import Project="C:\Users\PeterZhong\AppData\Local\Programs\ArcGIS\Pro\bin\Esri.ProApp.SDK.Desktop.targets" Condition="Exists('C:\Users\PeterZhong\AppData\Local\Programs\ArcGIS\Pro\bin\Esri.ProApp.SDK.Desktop.targets') AND !Exists('Esri.ArcGISPro.Extensions.targets')" />
|
||||
</Project>
|
||||
|
||||
@ -18,6 +18,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using log4net.Config;
|
||||
|
||||
namespace LinkToolAddin
|
||||
{
|
||||
@ -42,6 +43,7 @@ namespace LinkToolAddin
|
||||
}
|
||||
|
||||
#endregion Overrides
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
17
client/CallArcGISPro.cs
Normal file
17
client/CallArcGISPro.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using LinkToolAddin.server;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LinkToolAddin.client;
|
||||
|
||||
public class CallArcGISPro
|
||||
{
|
||||
public static string CallArcGISProTool(Dictionary<string,string> parameters)
|
||||
{
|
||||
// Call the ArcGIS Pro method and get the result
|
||||
var result = server.CallArcGISPro.CallArcGISProTool(parameters["toolName"], JsonConvert.DeserializeObject<List<string>>(parameters["toolParams"]));
|
||||
|
||||
// Serialize the result back to a JSON string
|
||||
return JsonConvert.SerializeObject(result);
|
||||
}
|
||||
}
|
||||
29
host/CallMcp.cs
Normal file
29
host/CallMcp.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using LinkToolAddin.server;
|
||||
using log4net;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LinkToolAddin.host
|
||||
{
|
||||
public class CallMcp
|
||||
{
|
||||
private static readonly ILog log = LogManager.GetLogger(typeof(CallMcp));
|
||||
public static string CallInnerMcpTool(string jsonRpcString)
|
||||
{
|
||||
log.Info("通过反射调用内部MCP工具");
|
||||
var jsonRpcEntity = JsonConvert.DeserializeObject<JsonRpcEntity>(jsonRpcString);
|
||||
|
||||
Type type = Type.GetType("LinkToolAddin.client."+jsonRpcEntity.Method.Split('.')[0]);
|
||||
MethodInfo method = type.GetMethod(jsonRpcEntity.Method.Split('.')[1],BindingFlags.Public | BindingFlags.Static);
|
||||
string result = (string)method.Invoke(null, new object[] { jsonRpcEntity.Params });
|
||||
|
||||
// 将结果序列化为 JSON 字符串
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
235
resource/DocDb.cs
Normal file
235
resource/DocDb.cs
Normal file
@ -0,0 +1,235 @@
|
||||
// <auto-generated />
|
||||
//
|
||||
// To parse this JSON data, add NuGet 'System.Text.Json' then do:
|
||||
//
|
||||
// using QuickType;
|
||||
//
|
||||
// var welcome = Welcome.FromJson(jsonString);
|
||||
#nullable enable
|
||||
#pragma warning disable CS8618
|
||||
#pragma warning disable CS8601
|
||||
#pragma warning disable CS8603
|
||||
|
||||
namespace QuickType
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Globalization;
|
||||
|
||||
public partial class DocDb
|
||||
{
|
||||
[JsonPropertyName("Code")]
|
||||
public string Code { get; set; }
|
||||
|
||||
[JsonPropertyName("Data")]
|
||||
public Data Data { get; set; }
|
||||
|
||||
[JsonPropertyName("Message")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[JsonPropertyName("RequestId")]
|
||||
public string RequestId { get; set; }
|
||||
|
||||
[JsonPropertyName("Status")]
|
||||
public long Status { get; set; }
|
||||
|
||||
[JsonPropertyName("Success")]
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
|
||||
public partial class Data
|
||||
{
|
||||
[JsonPropertyName("Nodes")]
|
||||
public List<Node> Nodes { get; set; }
|
||||
}
|
||||
|
||||
public partial class Node
|
||||
{
|
||||
[JsonPropertyName("Metadata")]
|
||||
public Metadata Metadata { get; set; }
|
||||
|
||||
[JsonPropertyName("Score")]
|
||||
public double Score { get; set; }
|
||||
|
||||
[JsonPropertyName("Text")]
|
||||
public string Text { get; set; }
|
||||
}
|
||||
|
||||
public partial class Metadata
|
||||
{
|
||||
[JsonPropertyName("parent")]
|
||||
public string Parent { get; set; }
|
||||
|
||||
[JsonPropertyName("file_path")]
|
||||
public Uri FilePath { get; set; }
|
||||
|
||||
[JsonPropertyName("image_url")]
|
||||
public List<Uri> ImageUrl { get; set; }
|
||||
|
||||
[JsonPropertyName("nid")]
|
||||
public string Nid { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[JsonPropertyName("doc_id")]
|
||||
public string DocId { get; set; }
|
||||
|
||||
[JsonPropertyName("content")]
|
||||
public string Content { get; set; }
|
||||
|
||||
[JsonPropertyName("workspace_id")]
|
||||
public string WorkspaceId { get; set; }
|
||||
|
||||
[JsonPropertyName("hier_title")]
|
||||
public string HierTitle { get; set; }
|
||||
|
||||
[JsonPropertyName("doc_name")]
|
||||
public string DocName { get; set; }
|
||||
|
||||
[JsonPropertyName("pipeline_id")]
|
||||
public string PipelineId { get; set; }
|
||||
|
||||
[JsonPropertyName("_id")]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
public partial class Welcome
|
||||
{
|
||||
public static Welcome FromJson(string json) => JsonSerializer.Deserialize<Welcome>(json, QuickType.Converter.Settings);
|
||||
}
|
||||
|
||||
public static class Serialize
|
||||
{
|
||||
public static string ToJson(this Welcome self) => JsonSerializer.Serialize(self, QuickType.Converter.Settings);
|
||||
}
|
||||
|
||||
internal static class Converter
|
||||
{
|
||||
public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)
|
||||
{
|
||||
Converters =
|
||||
{
|
||||
new DateOnlyConverter(),
|
||||
new TimeOnlyConverter(),
|
||||
IsoDateTimeOffsetConverter.Singleton
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public class DateOnlyConverter : JsonConverter<DateOnly>
|
||||
{
|
||||
private readonly string serializationFormat;
|
||||
public DateOnlyConverter() : this(null) { }
|
||||
|
||||
public DateOnlyConverter(string? serializationFormat)
|
||||
{
|
||||
this.serializationFormat = serializationFormat ?? "yyyy-MM-dd";
|
||||
}
|
||||
|
||||
public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var value = reader.GetString();
|
||||
return DateOnly.Parse(value!);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options)
|
||||
=> writer.WriteStringValue(value.ToString(serializationFormat));
|
||||
}
|
||||
|
||||
public class TimeOnlyConverter : JsonConverter<TimeOnly>
|
||||
{
|
||||
private readonly string serializationFormat;
|
||||
|
||||
public TimeOnlyConverter() : this(null) { }
|
||||
|
||||
public TimeOnlyConverter(string? serializationFormat)
|
||||
{
|
||||
this.serializationFormat = serializationFormat ?? "HH:mm:ss.fff";
|
||||
}
|
||||
|
||||
public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var value = reader.GetString();
|
||||
return TimeOnly.Parse(value!);
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options)
|
||||
=> writer.WriteStringValue(value.ToString(serializationFormat));
|
||||
}
|
||||
|
||||
internal class IsoDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
|
||||
{
|
||||
public override bool CanConvert(Type t) => t == typeof(DateTimeOffset);
|
||||
|
||||
private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
|
||||
|
||||
private DateTimeStyles _dateTimeStyles = DateTimeStyles.RoundtripKind;
|
||||
private string? _dateTimeFormat;
|
||||
private CultureInfo? _culture;
|
||||
|
||||
public DateTimeStyles DateTimeStyles
|
||||
{
|
||||
get => _dateTimeStyles;
|
||||
set => _dateTimeStyles = value;
|
||||
}
|
||||
|
||||
public string? DateTimeFormat
|
||||
{
|
||||
get => _dateTimeFormat ?? string.Empty;
|
||||
set => _dateTimeFormat = (string.IsNullOrEmpty(value)) ? null : value;
|
||||
}
|
||||
|
||||
public CultureInfo Culture
|
||||
{
|
||||
get => _culture ?? CultureInfo.CurrentCulture;
|
||||
set => _culture = value;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
|
||||
{
|
||||
string text;
|
||||
|
||||
|
||||
if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
|
||||
|| (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
|
||||
{
|
||||
value = value.ToUniversalTime();
|
||||
}
|
||||
|
||||
text = value.ToString(_dateTimeFormat ?? DefaultDateTimeFormat, Culture);
|
||||
|
||||
writer.WriteStringValue(text);
|
||||
}
|
||||
|
||||
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
string? dateText = reader.GetString();
|
||||
|
||||
if (string.IsNullOrEmpty(dateText) == false)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_dateTimeFormat))
|
||||
{
|
||||
return DateTimeOffset.ParseExact(dateText, _dateTimeFormat, Culture, _dateTimeStyles);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DateTimeOffset.Parse(dateText, Culture, _dateTimeStyles);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(DateTimeOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static readonly IsoDateTimeOffsetConverter Singleton = new IsoDateTimeOffsetConverter();
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS8618
|
||||
#pragma warning restore CS8601
|
||||
#pragma warning restore CS8603
|
||||
9
resource/GpToolDb.cs
Normal file
9
resource/GpToolDb.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace LinkToolAddin.resource;
|
||||
|
||||
public class GpToolDb
|
||||
{
|
||||
public string toolName { get; set; }
|
||||
public string toolDescription { get; set; }
|
||||
public string exeName { get; set; }
|
||||
public string toolParma { get; set; }
|
||||
}
|
||||
8
resource/PromptDb.cs
Normal file
8
resource/PromptDb.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace LinkToolAddin.resource;
|
||||
|
||||
public class PromptDb
|
||||
{
|
||||
public string promptName { get; set; }
|
||||
public string promptDescription { get; set; }
|
||||
public string promptContent { get; set; }
|
||||
}
|
||||
23
server/CallArcGISPro.cs
Normal file
23
server/CallArcGISPro.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ArcGIS.Desktop.Framework.Dialogs;
|
||||
|
||||
namespace LinkToolAddin.server;
|
||||
|
||||
public class CallArcGISPro
|
||||
{
|
||||
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(CallArcGISPro));
|
||||
public static JsonRpcResultEntity CallArcGISProTool(string methodName, List<string> methodParams)
|
||||
{
|
||||
// Simulate a call to ArcGIS Pro and return a success response
|
||||
var successResponse = new JsonRpcSuccessEntity
|
||||
{
|
||||
Jsonrpc = "2.0",
|
||||
Id = 1,
|
||||
Result = $"ArcGIS Pro {methodName} method called successfully"
|
||||
};
|
||||
log.Info($"ArcGIS Pro {methodName} method called successfully");
|
||||
MessageBox.Show($"ArcGIS Pro {methodName} method called successfully", "Test JsonRpc");
|
||||
return successResponse;
|
||||
}
|
||||
}
|
||||
25
server/JsonRpcEntity.cs
Normal file
25
server/JsonRpcEntity.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LinkToolAddin.server
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
public partial class JsonRpcEntity
|
||||
{
|
||||
[JsonProperty("jsonrpc")]
|
||||
public string Jsonrpc { get; set; }
|
||||
|
||||
[JsonProperty("method")]
|
||||
public string Method { get; set; }
|
||||
|
||||
[JsonProperty("params")]
|
||||
public Dictionary<string,string> Params { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
}
|
||||
25
server/JsonRpcErrorEntity.cs
Normal file
25
server/JsonRpcErrorEntity.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace LinkToolAddin.server
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public partial class JsonRpcErrorEntity
|
||||
{
|
||||
[JsonProperty("jsonrpc")]
|
||||
public string Jsonrpc { get; set; }
|
||||
|
||||
[JsonProperty("error")]
|
||||
public Error Error { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
public partial class Error
|
||||
{
|
||||
[JsonProperty("code")]
|
||||
public long Code { get; set; }
|
||||
|
||||
[JsonProperty("message")]
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
||||
15
server/JsonRpcResultEntity.cs
Normal file
15
server/JsonRpcResultEntity.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LinkToolAddin.server
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public partial class JsonRpcResultEntity
|
||||
{
|
||||
[JsonProperty("jsonrpc")]
|
||||
public string Jsonrpc { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
}
|
||||
16
server/JsonRpcSuccessEntity.cs
Normal file
16
server/JsonRpcSuccessEntity.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace LinkToolAddin.server
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
|
||||
public partial class JsonRpcSuccessEntity : JsonRpcResultEntity
|
||||
{
|
||||
[JsonProperty("jsonrpc")]
|
||||
public string Jsonrpc { get; set; }
|
||||
|
||||
[JsonProperty("result")]
|
||||
public string Result { get; set; }
|
||||
|
||||
[JsonProperty("id")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
}
|
||||
@ -22,13 +22,7 @@
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<DockPanel Grid.Row="0" LastChildFill="true" KeyboardNavigation.TabNavigation="Local" Height="30">
|
||||
<TextBlock Text="{Binding Heading}" Style="{DynamicResource Esri_TextBlockDockPaneHeader}">
|
||||
<TextBlock.ToolTip>
|
||||
<WrapPanel Orientation="Vertical" MaxWidth="300">
|
||||
<TextBlock Text="{Binding Heading}" TextWrapping="Wrap"/>
|
||||
</WrapPanel>
|
||||
</TextBlock.ToolTip>
|
||||
</TextBlock>
|
||||
<Button Content="Test Server" Name="TestServer" Click="TestServer_OnClick"></Button>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -1,18 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using log4net.Appender;
|
||||
using log4net.Config;
|
||||
using log4net.Layout;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LinkToolAddin.ui.dockpane
|
||||
{
|
||||
@ -21,9 +23,54 @@ namespace LinkToolAddin.ui.dockpane
|
||||
/// </summary>
|
||||
public partial class DialogDockpaneView : UserControl
|
||||
{
|
||||
private static ILog log = LogManager.GetLogger(typeof(DialogDockpaneView));
|
||||
|
||||
public DialogDockpaneView()
|
||||
{
|
||||
InitLogger();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void TestServer_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
log.Info("TestServer Clicked");
|
||||
string jsonRpcString = @"{""jsonrpc"":""2.0"",""method"":""CallArcGISPro.CallArcGISProTool"",""params"":{""toolName"":""Testbbb"",""toolParams"":""[\""aa\"",\""bbb\""]""},""id"":1}";
|
||||
LinkToolAddin.host.CallMcp.CallInnerMcpTool(jsonRpcString);
|
||||
}
|
||||
|
||||
protected void InitLogger()
|
||||
{
|
||||
// 1. 创建控制台输出器(Appender)
|
||||
var consoleAppender = new ConsoleAppender
|
||||
{
|
||||
Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"),
|
||||
Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别
|
||||
};
|
||||
consoleAppender.ActivateOptions(); // 激活配置
|
||||
|
||||
// 2. 创建文件滚动输出器(按大小滚动)
|
||||
var fileAppender = new RollingFileAppender
|
||||
{
|
||||
File = Path.Combine("Logs", "app.log"), // 日志文件路径
|
||||
AppendToFile = true, // 追加模式
|
||||
RollingStyle = RollingFileAppender.RollingMode.Size, // 按文件大小滚动
|
||||
MaxSizeRollBackups = 10, // 保留 10 个历史文件
|
||||
MaximumFileSize = "1MB", // 单个文件最大 1MB
|
||||
StaticLogFileName = true, // 固定文件名(否则自动追加序号)
|
||||
Layout = new PatternLayout("%date [%thread] %-5level %logger - %message%newline"),
|
||||
Threshold = log4net.Core.Level.Info // 仅输出 Info 及以上级别
|
||||
};
|
||||
fileAppender.ActivateOptions(); // 激活配置
|
||||
|
||||
// 3. 直接通过 BasicConfigurator 注册 Appender
|
||||
BasicConfigurator.Configure(consoleAppender, fileAppender);
|
||||
|
||||
log = LogManager.GetLogger(typeof(DialogDockpaneView));
|
||||
|
||||
// 测试日志输出
|
||||
log.Debug("Debug 日志(控制台可见)");
|
||||
log.Info("Info 日志(控制台和文件可见)");
|
||||
log.Error("Error 日志(严重问题)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
|
||||
namespace LinkToolAddin.ui.dockpane
|
||||
{
|
||||
@ -56,6 +60,7 @@ namespace LinkToolAddin.ui.dockpane
|
||||
{
|
||||
protected override void OnClick()
|
||||
{
|
||||
|
||||
DialogDockpaneViewModel.Show();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user