Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/scripts/prepare_markdown_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import argparse
from pathlib import Path


class RepositoryLinks:
def __init__(self, root):
self.root = Path(root).resolve()

def prepare(self):
docs = self.root / "docs"
if not docs.is_dir():
raise ValueError(f"Missing documentation directory: {docs}")
if docs.is_symlink():
raise ValueError(f"Refusing to rewrite a documentation symlink: {docs}")

changed = 0
prefixes = (
"https://github.com/modelcontextprotocol/csharp-sdk/tree/main/",
"https://github.com/modelcontextprotocol/csharp-sdk/blob/main/",
)
for path in docs.rglob("*.md"):
if path.is_symlink():
raise ValueError(f"Refusing to rewrite a documentation symlink: {path}")
text = path.read_text(encoding="utf-8")
updated = text
for prefix in prefixes:
updated = updated.replace(prefix, "/")
if updated != text:
path.write_text(updated, encoding="utf-8")
changed += 1
return changed


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Resolve this repository's main-branch links against the proposed checkout for mlc."
)
parser.add_argument("root")
arguments = parser.parse_args()
count = RepositoryLinks(arguments.root).prepare()
print(f"Prepared repository-local links in {count} Markdown files; mlc still validates each target.")
47 changes: 47 additions & 0 deletions .github/scripts/test_prepare_markdown_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from pathlib import Path
import tempfile
import unittest

from prepare_markdown_links import RepositoryLinks


class RepositoryLinksTests(unittest.TestCase):
def setUp(self):
self.directory = tempfile.TemporaryDirectory()
self.addCleanup(self.directory.cleanup)
self.root = Path(self.directory.name)
(self.root / "docs").mkdir()

def test_main_links_become_checkout_paths_without_ignoring_missing_targets(self):
path = self.root / "docs" / "example.md"
path.write_text(
"[sample](https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples/SkillsServer)\n"
"[source](https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/missing.cs)\n",
encoding="utf-8",
)

self.assertEqual(RepositoryLinks(self.root).prepare(), 1)
self.assertEqual(
path.read_text(encoding="utf-8"),
"[sample](/samples/SkillsServer)\n[source](/src/missing.cs)\n",
)

def test_other_repositories_and_pinned_revisions_remain_web_links(self):
path = self.root / "docs" / "example.md"
original = (
"[other](https://github.com/other/project/tree/main/sample)\n"
"[pinned](https://github.com/modelcontextprotocol/csharp-sdk/tree/1234567/sample)\n"
"[relative](other.md)\n"
)
path.write_text(original, encoding="utf-8")

self.assertEqual(RepositoryLinks(self.root).prepare(), 0)
self.assertEqual(path.read_text(encoding="utf-8"), original)

def test_missing_documentation_is_not_a_success(self):
with self.assertRaises(ValueError):
RepositoryLinks(self.root / "absent").prepare()


if __name__ == "__main__":
unittest.main()
18 changes: 16 additions & 2 deletions .github/workflows/markdown-link-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@ name: Check Markdown links
on:
push:
branches: [ "main" ]
paths: "**.md"
paths:
- "**.md"
- ".github/scripts/prepare_markdown_links.py"
- ".github/scripts/test_prepare_markdown_links.py"
- ".github/workflows/markdown-link-check.yml"
pull_request:
branches: [ "main" ]
paths: "**.md"
paths:
- "**.md"
- ".github/scripts/prepare_markdown_links.py"
- ".github/scripts/test_prepare_markdown_links.py"
- ".github/workflows/markdown-link-check.yml"

permissions:
contents: read
Expand All @@ -18,6 +26,11 @@ jobs:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Resolve main-branch links against the proposed checkout
run: |
python3 -m unittest discover -s .github/scripts -p test_prepare_markdown_links.py
python3 .github/scripts/prepare_markdown_links.py .

- name: Markup Link Checker (mlc)
uses: becheran/mlc@7ec24825cefe0c9c8c6bac48430e1f69e3ec356e # v1.2.0
with:
Expand All @@ -26,6 +39,7 @@ jobs:
# Do not warn for learn.microsoft.com locale redirects.
# Do not warn for modelcontextprotocol.io homepage/spec redirects.
args: >-
--root-dir .
--ignore-links "xref:*"
--ignore-links "*samples/*?name=snippet_*"
--do-not-warn-for-redirect-to "https://learn.microsoft.com/en-us/*"
Expand Down
3 changes: 3 additions & 0 deletions ModelContextProtocol.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
<Project Path="samples/ProtectedMcpServer/ProtectedMcpServer.csproj" />
<Project Path="samples/QuickstartClient/QuickstartClient.csproj" />
<Project Path="samples/QuickstartWeatherServer/QuickstartWeatherServer.csproj" />
<Project Path="samples/SkillsClient/SkillsClient.csproj" />
<Project Path="samples/SkillsServer/SkillsServer.csproj" />
<Project Path="samples/TasksExtension/TasksExtension.csproj" />
<Project Path="samples/TestServerWithHosting/TestServerWithHosting.csproj" />
<Project Path="samples/WeatherAppServer/WeatherAppServer.csproj" />
Expand All @@ -69,6 +71,7 @@
<Project Path="src/ModelContextProtocol.AspNetCore/ModelContextProtocol.AspNetCore.csproj" />
<Project Path="src/ModelContextProtocol.Core/ModelContextProtocol.Core.csproj" />
<Project Path="src/ModelContextProtocol.Extensions.Apps/ModelContextProtocol.Extensions.Apps.csproj" />
<Project Path="src/ModelContextProtocol.Extensions.Skills/ModelContextProtocol.Extensions.Skills.csproj" />
<Project Path="src/ModelContextProtocol.Extensions.Tasks/ModelContextProtocol.Extensions.Tasks.csproj" />
<Project Path="src/ModelContextProtocol/ModelContextProtocol.csproj" />
</Folder>
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ The SDK packages are:

- **[ModelContextProtocol.Extensions.Apps](https://www.nuget.org/packages/ModelContextProtocol.Extensions.Apps)** [![NuGet version](https://img.shields.io/nuget/v/ModelContextProtocol.Extensions.Apps.svg)](https://www.nuget.org/packages/ModelContextProtocol.Extensions.Apps) - MCP Apps extension for building interactive UI applications that render inside MCP hosts.

- **[ModelContextProtocol.Extensions.Skills](https://www.nuget.org/packages/ModelContextProtocol.Extensions.Skills)** [![NuGet version](https://img.shields.io/nuget/v/ModelContextProtocol.Extensions.Skills.svg)](https://www.nuget.org/packages/ModelContextProtocol.Extensions.Skills) - MCP Skills extension for serving and consuming Agent Skills with verifiable file manifests.

- **[ModelContextProtocol.Extensions.Tasks](https://www.nuget.org/packages/ModelContextProtocol.Extensions.Tasks)** [![NuGet version](https://img.shields.io/nuget/v/ModelContextProtocol.Extensions.Tasks.svg)](https://www.nuget.org/packages/ModelContextProtocol.Extensions.Tasks) - MCP Tasks extension for running long-running tool invocations asynchronously with status polling and input requests.

## Getting Started
Expand Down
1 change: 1 addition & 0 deletions docs/concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ To install the SDK and build your first MCP client and server, see [Getting star
| - | - |
| [MCP Apps](apps/apps.md) | Learn how to use the MCP Apps extension to deliver interactive UIs from MCP servers. |
| [Tasks](tasks/tasks.md) | Learn how to use task-based execution for long-running operations that can be polled for status and results. |
| [Skills](skills/skills.md) | Learn how to serve and consume Agent Skills over MCP, with verifiable file manifests. |
| [Identity and Roles](identity/identity.md) | Learn how to access caller identity and roles in MCP tool, prompt, and resource handlers. |
Loading