自主实现JSON Schema生成,接入数据查看工具
This commit is contained in:
parent
b6397e5db3
commit
3b1f65b3ba
@ -24,19 +24,49 @@ public class ArcGisPro
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[McpServerTool, Description("查看指定数据的属性,包括坐标系、范围、数据类型等")]
|
[McpServerTool, Description("查看指定数据的坐标系、范围、几何类型、是否有Z坐标和M坐标,获取字段列表等")]
|
||||||
public static async Task<JsonRpcResultEntity> DataProperty(string datasetPath,string dataName)
|
public static async Task<JsonRpcResultEntity> DataProperty(string datasetPath,string dataName)
|
||||||
|
{
|
||||||
|
JsonRpcResultEntity result = new JsonRpcResultEntity();
|
||||||
|
await QueuedTask.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
using Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(datasetPath)));
|
using Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(datasetPath)));
|
||||||
FeatureClass featureClass = gdb.OpenDataset<FeatureClass>(dataName);
|
FeatureClass featureClass = gdb.OpenDataset<FeatureClass>(dataName);
|
||||||
FeatureClassDefinition featureClassDefinition = featureClass.GetDefinition();
|
FeatureClassDefinition featureClassDefinition = featureClass.GetDefinition();
|
||||||
JsonRpcResultEntity result = new JsonRpcSuccessEntity()
|
SpatialReference spatialReference = featureClassDefinition.GetSpatialReference();
|
||||||
|
GeometryType geometryType = featureClassDefinition.GetShapeType();
|
||||||
|
result = new JsonRpcSuccessEntity()
|
||||||
{
|
{
|
||||||
Id = 1,
|
Id = 1,
|
||||||
Result = JsonConvert.SerializeObject(featureClassDefinition)
|
Result = JsonConvert.SerializeObject(new Dictionary<string, object>()
|
||||||
|
{
|
||||||
|
{"spatialReference", spatialReference.Name+"(WKID:"+spatialReference.Wkid+")"},
|
||||||
|
{"dataName", dataName},
|
||||||
|
{"geometryType", geometryType.ToString()},
|
||||||
|
{"hasZValue", featureClassDefinition.HasZ()},
|
||||||
|
{"hasMValue", featureClassDefinition.HasM()},
|
||||||
|
{"fields",featureClassDefinition.GetFields()}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
result = new JsonRpcErrorEntity()
|
||||||
|
{
|
||||||
|
Error = new Error()
|
||||||
|
{
|
||||||
|
Message = ex.Message
|
||||||
|
},
|
||||||
|
Id = 1
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
[McpServerTool, Description("列出gdb数据库中的所有数据名称")]
|
[McpServerTool, Description("列出gdb数据库中的所有数据名称")]
|
||||||
public static async Task<JsonRpcResultEntity> ListData(string gdbPath)
|
public static async Task<JsonRpcResultEntity> ListData(string gdbPath)
|
||||||
|
|||||||
25
client/tool/KnowledgeBase.cs
Normal file
25
client/tool/KnowledgeBase.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LinkToolAddin.host.llm.entity;
|
||||||
|
using LinkToolAddin.resource;
|
||||||
|
using LinkToolAddin.server;
|
||||||
|
using ModelContextProtocol.Server;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.client.tool;
|
||||||
|
|
||||||
|
public class KnowledgeBase
|
||||||
|
{
|
||||||
|
[McpServerTool, Description("可以查询ArcGIS Pro的帮助文档获取关于地理处理工具使用参数的说明")]
|
||||||
|
public static async Task<JsonRpcResultEntity> QueryArcgisHelpDoc(string query)
|
||||||
|
{
|
||||||
|
DocDb docDb = new DocDb("sk-db177155677e438f832860e7f4da6afc", DocDb.KnowledgeBase.ArcGISProHelpDoc);
|
||||||
|
KnowledgeResult knowledgeResult = await docDb.Retrieve(query);
|
||||||
|
JsonRpcResultEntity result = new JsonRpcSuccessEntity()
|
||||||
|
{
|
||||||
|
Result = JsonConvert.SerializeObject(knowledgeResult.ChunkList),
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
150
common/JsonSchemaGenerator.cs
Normal file
150
common/JsonSchemaGenerator.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace LinkToolAddin.common;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
public static class JsonSchemaGenerator
|
||||||
|
{
|
||||||
|
public static string GenerateJsonSchema(MethodInfo methodInfo)
|
||||||
|
{
|
||||||
|
var parameters = methodInfo.GetParameters();
|
||||||
|
var properties = new Dictionary<string, object>();
|
||||||
|
var required = new List<string>();
|
||||||
|
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
var paramName = param.Name ?? throw new InvalidOperationException("参数没有名称。");
|
||||||
|
var paramSchema = GenerateSchemaForType(param.ParameterType);
|
||||||
|
properties[paramName] = paramSchema;
|
||||||
|
|
||||||
|
if (!param.IsOptional)
|
||||||
|
{
|
||||||
|
required.Add(paramName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var schemaRoot = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "$schema", "http://json-schema.org/draft-07/schema#" },
|
||||||
|
{ "type", "object" },
|
||||||
|
{ "properties", properties }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (required.Count > 0)
|
||||||
|
{
|
||||||
|
schemaRoot["required"] = required;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = new JsonSerializerOptions { WriteIndented = true };
|
||||||
|
return JsonSerializer.Serialize(schemaRoot, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object GenerateSchemaForType(Type type)
|
||||||
|
{
|
||||||
|
// 处理可空类型
|
||||||
|
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||||
|
{
|
||||||
|
var underlyingType = Nullable.GetUnderlyingType(type);
|
||||||
|
return new[] { GenerateSchemaForType(underlyingType), "null" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理集合类型(数组或IEnumerable<T>)
|
||||||
|
if (IsCollectionType(type, out Type elementType))
|
||||||
|
{
|
||||||
|
return new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "type", "array" },
|
||||||
|
{ "items", GenerateSchemaForType(elementType) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理基本类型(int, string, bool, etc.)
|
||||||
|
if (IsPrimitiveType(type))
|
||||||
|
{
|
||||||
|
string jsonType = MapClrTypeToJsonType(type);
|
||||||
|
var schema = new Dictionary<string, object> { { "type", jsonType } };
|
||||||
|
|
||||||
|
if (type == typeof(DateTime))
|
||||||
|
schema["format"] = "date-time";
|
||||||
|
else if (type == typeof(Guid))
|
||||||
|
schema["format"] = "uuid";
|
||||||
|
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理复杂类型(类、结构体)
|
||||||
|
if (type.IsClass || type.IsValueType)
|
||||||
|
{
|
||||||
|
var props = new Dictionary<string, object>();
|
||||||
|
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||||
|
{
|
||||||
|
props[prop.Name] = GenerateSchemaForType(prop.PropertyType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "type", "object" },
|
||||||
|
{ "properties", props }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认情况
|
||||||
|
return new Dictionary<string, object> { { "type", "any" } };
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCollectionType(Type type, out Type elementType)
|
||||||
|
{
|
||||||
|
if (type == typeof(string))
|
||||||
|
{
|
||||||
|
elementType = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsArray)
|
||||||
|
{
|
||||||
|
elementType = type.GetElementType();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
var genericTypeDef = type.GetGenericTypeDefinition();
|
||||||
|
if (genericTypeDef == typeof(IEnumerable<>) ||
|
||||||
|
genericTypeDef == typeof(List<>) ||
|
||||||
|
genericTypeDef == typeof(Collection<>))
|
||||||
|
{
|
||||||
|
elementType = type.GetGenericArguments()[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elementType = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPrimitiveType(Type type)
|
||||||
|
{
|
||||||
|
return type.IsPrimitive || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(Guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string MapClrTypeToJsonType(Type type)
|
||||||
|
{
|
||||||
|
if (type == typeof(int) || type == typeof(short) || type == typeof(long) ||
|
||||||
|
type == typeof(uint) || type == typeof(ushort) || type == typeof(ulong))
|
||||||
|
return "integer";
|
||||||
|
if (type == typeof(float) || type == typeof(double) || type == typeof(decimal))
|
||||||
|
return "number";
|
||||||
|
if (type == typeof(bool))
|
||||||
|
return "boolean";
|
||||||
|
if (type == typeof(string))
|
||||||
|
return "string";
|
||||||
|
if (type == typeof(DateTime) || type == typeof(Guid))
|
||||||
|
return "string";
|
||||||
|
return "any";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -30,6 +30,7 @@ using Newtonsoft.Json.Linq;
|
|||||||
using Newtonsoft.Json.Schema;
|
using Newtonsoft.Json.Schema;
|
||||||
using Newtonsoft.Json.Schema.Generation;
|
using Newtonsoft.Json.Schema.Generation;
|
||||||
using Tool = LinkToolAddin.host.mcp.Tool;
|
using Tool = LinkToolAddin.host.mcp.Tool;
|
||||||
|
using LinkToolAddin.common;
|
||||||
|
|
||||||
namespace LinkToolAddin.host;
|
namespace LinkToolAddin.host;
|
||||||
|
|
||||||
@ -471,7 +472,7 @@ public class Gateway
|
|||||||
{
|
{
|
||||||
string methodName = method.Name;
|
string methodName = method.Name;
|
||||||
string methodDescription = method.GetCustomAttribute<DescriptionAttribute>()?.Description;
|
string methodDescription = method.GetCustomAttribute<DescriptionAttribute>()?.Description;
|
||||||
string methodParamSchema = GenerateMethodParamSchema(method);
|
string methodParamSchema = LinkToolAddin.common.JsonSchemaGenerator.GenerateJsonSchema(method);
|
||||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||||
{
|
{
|
||||||
Tool = new Tool
|
Tool = new Tool
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user