Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .agents/skills/docker-and-compose/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ One multi-stage `Dockerfile` does everything the pipeline needs:

The Lambda template's `run` stage is the AWS Lambda .NET base image instead. It runs as user `65534` from `/var/task`, keeps its database in `/tmp`, and has no `HEALTHCHECK`. Its compose file runs the collector and the Aspire dashboard as well. Compose maps the runtime interface emulator to port 9000, so the function can be invoked with a `POST` to `/2015-03-31/functions/function/invocations`.

The `demo` profile adds Open WebUI for a chat over the tools (`mcp-inspector`). Keep it behind the profile so plain `docker compose up` stays the same. Solutions generated with authentication on leave it out.

## Steps

1. Keep restore before `COPY . .` so a code change doesn't redo the restore layer. A new project folder needs nothing extra; the loops pick up every `src/*/*.csproj` and `tests/*/*.csproj`.
Expand Down
4 changes: 4 additions & 0 deletions .agents/skills/mcp-inspector/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ metadata:
5. Find the tool call in the Aspire dashboard if something looks wrong: its trace shows the tool, the use case and each SQL command, and its logs sit beside it (`telemetry`).
6. With authentication on, the Inspector needs a token from your authority. Leave `Authentication:Authority` empty for local checks.

## Chat demo

To try the tools the way a model does, add the optional `demo` profile: `docker compose --profile demo up -d --build`. It starts [Open WebUI](https://github.com/open-webui/open-webui) at <http://localhost:3000>, already connected to the server and using Kilo's free gateway as the model, with no account or key. It's online only, and your prompts and tool results go to Kilo, a third party, so use it with sample data. Plain `docker compose up` doesn't start it, and solutions created with `--include-auth` leave it out, because Open WebUI has no token to send.

## Don't

- Expose port 6274 beyond `127.0.0.1`. The Inspector can call every tool.
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/template-authoring/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Every optional feature is a toggle, and every toggle has the same shape, so peop

Off means absent, not switched off. Files that only exist for a toggle go in a `(!include<Feature>)` exclude list under `sources` in `template.json`, and code inside shared files is wrapped so `dotnet new` can leave it out. In C#, `#if includeAuth` and `#endif` start at the beginning of the line, with no brackets (the build fails IDE0047 and IDE0055 otherwise). In project files it's `<!--#if (includeAuth) -->` and `<!--#endif -->`, and in `appsettings.json` it's `//#if (includeAuth)` and `//#endif`. A file type the template engine doesn't know, such as the GraphQL schema snapshot, gets `#if (includeAuth)` and `#endif` lines through `SpecialCustomOperations` in `template.json`.

The `chat` service and its volume in `docker-compose.yml` sit in `#if (!includeAuth)` blocks, because Open WebUI has no token to send. A shipped skill must describe that without naming the symbol: Verify Template fails if the word survives in a generated solution.

The repository itself stays all on. The Presentation project and the presentation integration tests define each toggle's constant, such as `includeAuth`, inside `<!--#if (false) -->`, which `dotnet new` always removes. The template's skills and `AGENTS.md` ship either way.

A toggle's inputs, such as `authority` and `audience`, are separate symbols, enabled with `isEnabled` and made required with `isRequired` only when the toggle is on. Only `dotnet new` honours those two. Visual Studio and Rider show every input whatever the toggle says ([dotnet/templating#7860](https://github.com/dotnet/templating/issues/7860)), and Rider lists checkboxes first, then text fields in alphabetical order by label. So an input's label starts with its feature, such as "Authentication authority", to sit right under its checkbox, and its IDE description says it's only used when that box is ticked. A toggle that needs another one says so in its conditions, such as `(includeTests && includeArchitectureTests)`. Verify Template checks the defaults, everything on, everything off, and each toggle flipped on its own.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ Yes, the sample movies are named by a corporate buzzword generator, and the crit

Curl is a fine way to prove it works and a terrible way to spend an afternoon. Open the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) at <http://localhost:6274> instead. It's already pointed at the server, so flip the switch to connect and open **Tools**.

For a chat over the same tools, `docker compose --profile demo up -d --build` adds [Open WebUI](https://github.com/open-webui/open-webui) at <http://localhost:3000>. It's optional and online only, and your prompts go to Kilo's free gateway, a third party. [Run it](docs/RUN.md#chat-demo) has the details.

There are six tools shaped around jobs rather than tables: `movies_search`, `movies_get`, `authors_search`, `reviews_list`, `reviews_write` and `reviews_delete`. Each has a description written for agents and hints that say what's read-only and what's destructive. Lists come back ten at a time, with a `totalCount` and a `nextOffset` when there's more to come, so an agent doesn't drown in its own context window. There are resources for every movie, author and review, and prompts for jobs like comparing two movies. Its logs, traces and metrics land in the [Aspire dashboard](https://learn.microsoft.com/dotnet/aspire/fundamentals/dashboard/standalone) at <http://localhost:18888>.

No Docker? `dotnet run --project src/Presentation` works too. Every other way to run it, from plain `docker run` to stamping a version into the image, is in [docs/RUN.md](docs/RUN.md).
Expand Down
30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,38 @@ services:
ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS: "true"
networks:
- cleanmodelcontextprotocol_network
#if (!includeAuth)
# Optional chat over the MCP server: docker compose --profile demo up -d --build. Prompts go to Kilo, a third party.
chat:
image: ghcr.io/open-webui/open-webui:v0.13.0
profiles:
- demo
ports:
- "127.0.0.1:3000:8080"
environment:
# Kilo's free gateway takes no API key, and a dummy one gets a 401.
OPENAI_API_BASE_URL: https://api.kilo.ai/api/gateway
DEFAULT_MODELS: kilo-auto/free
ENABLE_OLLAMA_API: "False"
WEBUI_AUTH: "False"
TOOL_SERVER_CONNECTIONS: '[{"url":"http://api:8080/mcp","path":"","type":"mcp","auth_type":"none","key":"","config":{"enable":true},"info":{"id":"mcp","name":"MCP server"}}]'
# Turns the MCP server on in every chat, and leaves out Open WebUI's own tools so the model only sees ours.
DEFAULT_MODEL_METADATA: '{"toolIds":["server:mcp:mcp"],"capabilities":{"builtin_tools":false}}'
# These two skip the embedding model download from Hugging Face on first start.
OFFLINE_MODE: "True"
BYPASS_EMBEDDING_AND_RETRIEVAL: "True"
volumes:
- chat-data:/app/backend/data
networks:
- cleanmodelcontextprotocol_network
depends_on:
- api
#endif
volumes:
movie-reviews-data:
#if (!includeAuth)
chat-data:
#endif
networks:
cleanmodelcontextprotocol_network:
driver: bridge
11 changes: 11 additions & 0 deletions docs/RUN.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ To shut the containers down:
docker compose down
```


### Chat demo

Want to ask for things in plain English? The optional `demo` profile adds [Open WebUI](https://github.com/open-webui/open-webui), already connected to the server:

``` bash
docker compose --profile demo up -d --build
```

Open <http://localhost:3000>, dismiss the release notes and ask it to list the movies. It uses Kilo's free gateway as the model, so there's no account or key, but it only works online, and your prompts and tool results go to Kilo, a third party. Keep it to sample data. Solutions created with `--include-auth` leave it out, because Open WebUI has no token to send. Stop it with `docker compose --profile demo down`.

## Telemetry

The app always collects [OpenTelemetry](https://opentelemetry.io) traces and metrics, and exports them, along with its logs, only when `OTEL_EXPORTER_OTLP_ENDPOINT` is set. Every other standard `OTEL_*` variable works too, such as `OTEL_SERVICE_NAME`, `OTEL_EXPORTER_OTLP_PROTOCOL` and `OTEL_EXPORTER_OTLP_HEADERS`, so sending it to Grafana, Honeycomb, Seq or a collector is a settings change.
Expand Down
Loading