diff --git a/src/Neo.SmartContract.Template/README.md b/src/Neo.SmartContract.Template/README.md
index deafa501f..31f6bdf91 100644
--- a/src/Neo.SmartContract.Template/README.md
+++ b/src/Neo.SmartContract.Template/README.md
@@ -84,6 +84,7 @@ Project templates generate:
```
MyContract/
+├── .config/dotnet-tools.json
├── MyContract.cs # Main contract file
├── MyContract.csproj # Project file with proper references
└── README.md # Template-specific documentation
diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep11/.config/dotnet-tools.json b/src/Neo.SmartContract.Template/templates/neocontractnep11/.config/dotnet-tools.json
new file mode 100644
index 000000000..33d1b0eb0
--- /dev/null
+++ b/src/Neo.SmartContract.Template/templates/neocontractnep11/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "neo.compiler.csharp": {
+ "version": "TemplateNeoVersion",
+ "commands": [
+ "nccs"
+ ]
+ }
+ }
+}
diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj b/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj
index 8dbd3226d..c8572980a 100644
--- a/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj
+++ b/src/Neo.SmartContract.Template/templates/neocontractnep11/Nep11Contract.csproj
@@ -25,7 +25,8 @@
-
+
+
diff --git a/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj b/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj
index 8dbd3226d..c8572980a 100644
--- a/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj
+++ b/src/Neo.SmartContract.Template/templates/neocontractnep17/Nep17Contract.csproj
@@ -25,7 +25,8 @@
-
+
+
diff --git a/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj b/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj
index 8dbd3226d..c8572980a 100644
--- a/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj
+++ b/src/Neo.SmartContract.Template/templates/neocontractoracle/OracleRequest.csproj
@@ -25,7 +25,8 @@
-
+
+
diff --git a/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj b/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj
index 8dbd3226d..c8572980a 100644
--- a/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj
+++ b/src/Neo.SmartContract.Template/templates/neocontractowner/Ownable.csproj
@@ -25,7 +25,8 @@
-
+
+
diff --git a/tests/Neo.SmartContract.Template.UnitTests/templates/ContractTemplateToolManifestTests.cs b/tests/Neo.SmartContract.Template.UnitTests/templates/ContractTemplateToolManifestTests.cs
new file mode 100644
index 000000000..87b2d7bbd
--- /dev/null
+++ b/tests/Neo.SmartContract.Template.UnitTests/templates/ContractTemplateToolManifestTests.cs
@@ -0,0 +1,71 @@
+// Copyright (C) 2015-2026 The Neo Project.
+//
+// ContractTemplateToolManifestTests.cs file belongs to the neo project and is free
+// software distributed under the MIT software license, see the
+// accompanying file LICENSE in the main directory of the
+// repository or http://www.opensource.org/licenses/mit-license.php
+// for more details.
+//
+// Redistribution and use in source and binary forms with or without
+// modifications are permitted.
+
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.IO;
+using System.Linq;
+using System.Text.Json;
+using System.Xml.Linq;
+
+namespace Neo.SmartContract.Template.UnitTests.templates;
+
+[TestClass]
+public class ContractTemplateToolManifestTests
+{
+ private static readonly string TemplateRoot = Path.GetFullPath(
+ "../../../../../src/Neo.SmartContract.Template/templates");
+
+ [DataTestMethod]
+ [DataRow("neocontractnep11")]
+ [DataRow("neocontractnep17")]
+ [DataRow("neocontractoracle")]
+ [DataRow("neocontractowner")]
+ [DataRow("neocontractsolution")]
+ public void ContractTemplate_IncludesCompilerToolManifest(string templateName)
+ {
+ var manifestPath = Path.Combine(TemplateRoot, templateName, ".config", "dotnet-tools.json");
+ Assert.IsTrue(File.Exists(manifestPath), $"{templateName} is missing .config/dotnet-tools.json.");
+
+ using var document = JsonDocument.Parse(File.ReadAllText(manifestPath));
+ var root = document.RootElement;
+ var compiler = root.GetProperty("tools").GetProperty("neo.compiler.csharp");
+
+ Assert.AreEqual(1, root.GetProperty("version").GetInt32());
+ Assert.IsTrue(root.GetProperty("isRoot").GetBoolean());
+ Assert.AreEqual("TemplateNeoVersion", compiler.GetProperty("version").GetString());
+
+ var commands = compiler.GetProperty("commands");
+ Assert.AreEqual(1, commands.GetArrayLength());
+ Assert.AreEqual("nccs", commands[0].GetString());
+ }
+
+ [DataTestMethod]
+ [DataRow("neocontractnep11", "Nep11Contract.csproj")]
+ [DataRow("neocontractnep17", "Nep17Contract.csproj")]
+ [DataRow("neocontractoracle", "OracleRequest.csproj")]
+ [DataRow("neocontractowner", "Ownable.csproj")]
+ public void StandaloneContractTemplate_UsesLocalCompilerTool(
+ string templateName,
+ string projectName)
+ {
+ var project = XDocument.Load(Path.Combine(TemplateRoot, templateName, projectName));
+ var commands = project.Descendants("Exec")
+ .Select(element => (string?)element.Attribute("Command"))
+ .Where(command => command is not null)
+ .ToArray();
+
+ CollectionAssert.Contains(commands, "dotnet tool restore");
+ Assert.IsTrue(
+ commands.Any(command => command!.StartsWith("dotnet tool run nccs ", StringComparison.Ordinal)),
+ $"{projectName} must invoke nccs through the local tool manifest.");
+ }
+}