Skip to content

feat: add class decorators example#1893

Open
KKonstantinov wants to merge 2 commits intomainfrom
feature/example-decorators
Open

feat: add class decorators example#1893
KKonstantinov wants to merge 2 commits intomainfrom
feature/example-decorators

Conversation

@KKonstantinov
Copy link
Copy Markdown
Contributor

Adds a pair of self-contained examples showing how to author MCP tools, resources, and prompts as decorated methods on a class, in both decorator dialects TypeScript supports.

Motivation and Context

Follow-up to #116 ("Declarative, high-level MCP server API"). That thread evolved into a discussion of class-based @Tool / @Resource / @Prompt decorators as an alternative to the function-based McpServer API. The issue was closed as not planned — decorators in TS/JS only work on class methods, so shipping them in the SDK would impose an OO style on everyone — with the position that this pattern is straightforward for users to build themselves on top of the existing SDK. These examples are the reference implementation of exactly that: copy-paste-friendly proof that the pattern works end-to-end, with no SDK changes required.

The SDK's McpServer API is function-based: you call .tool(), .resource(), .prompt() at registration time. That works well, but a recurring question from users is "can I group related handlers onto a class and register them declaratively?" — the answer is yes, with a small amount of decorator plumbing and no new SDK dependency.

These examples show the full pattern end-to-end so users can copy ~60 lines into their own project:

  • @McpTool / @McpResource / @McpResourceTemplate / @McpPrompt method decorators
  • A registerClass(server, instance) helper that reflects over the class and wires each decorated method into McpServer
  • Config shapes derived from the spec types (Tool, Prompt, Resource, ResourceTemplateType) via Omit<…, identity>, so any spec-level field (icons, annotations, _meta, …) is automatically supported without touching the example

Because experimentalDecorators is project-wide in TypeScript, covering both dialects requires a second tsconfig — which is itself useful to document.

How Has This Been Tested?

  • Legacy example: pnpm tsx src/legacyClassDecoratorsExample.ts (uses the package's existing experimentalDecorators: true tsconfig).
  • Standard example: pnpm tsx --tsconfig=tsconfig.standard-decorators.json src/classDecoratorsExample.ts.
  • pnpm --filter @modelcontextprotocol/server-examples typecheck now runs tsgo against both tsconfigs, so the standard-decorators file is type-checked in CI.
  • Both examples expose the same tools/resources/prompts and produce identical behavior over stdio — verified by inspection against an MCP client.

Breaking Changes

None. These are additive example files; no SDK code changes.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Background references

Design notes

  • The two examples are intentionally near-identical at the call sites — the only differences are inside each decorator body ((target, propertyKey, descriptor) vs (value, context)) and how registerClass retrieves the collected metadata. This makes them easy to diff if you're porting one codebase to the other.
  • Neither example depends on reflect-metadata. The legacy version stashes arrays on the prototype; the standard version uses Stage-3's built-in context.metadata object.
  • The Symbol.metadata polyfill is guarded (??=) so it is a no-op on Node 22+.

@KKonstantinov KKonstantinov requested a review from a team as a code owner April 15, 2026 18:51
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 15, 2026

⚠️ No Changeset found

Latest commit: c80f0ab

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 15, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1893

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1893

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1893

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1893

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1893

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1893

commit: c80f0ab

Comment thread examples/server/src/classDecoratorsExample.ts
Comment thread examples/server/src/legacyClassDecoratorsExample.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant