Skip to content

Commit 769b395

Browse files
committed
enhance prompts exercise
1 parent 8f0353d commit 769b395

File tree

52 files changed

+2697
-288
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2697
-288
lines changed

exercises/03.resources/01.problem.simple/README.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Your goal:
1010
- Declare the `resources` capability on your server.
1111
- Register a simple resource called "credits" that provides information about
1212
the creator of the app. This resource should be available at the URI
13-
`meta://credits` and return a plain text string with the username of the app's
13+
`epicme://credits` and return a plain text string with the username of the app's
1414
creator.
1515

1616
This is your first taste of the MCP resources system. No need for dynamic

exercises/03.resources/01.problem.simple/src/resources.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { type EpicMeMCP } from './index.ts'
44

55
export async function initializeResources(agent: EpicMeMCP) {
6-
// 🐨 create a resource called "credits" with the URI meta://credits
6+
// 🐨 create a resource called "credits" with the URI epicme://credits
77
// this tool will return a string with the credits for the creators of the app
88
// so set the description to explain that
99
// 🐨 the handler accepts the uri and returns the contents array which should

exercises/03.resources/01.solution.simple/src/resources.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { type EpicMeMCP } from './index.ts'
44
export async function initializeResources(agent: EpicMeMCP) {
55
agent.server.resource(
66
'credits',
7-
'meta://credits',
7+
'epicme://credits',
88
{
99
description: 'Credits for the creators of the app',
1010
},

exercises/03.resources/02.problem.template/README.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
In this step, you'll use MCP's resource templates to expose a whole family of
55
resources—each with its own unique URI and data.
66

7-
Resource templates let you define parameterized resources, like `entry://{id}`
8-
or `tag://{id}`. This means clients can discover and read individual entries or
7+
Resource templates let you define parameterized resources, like `epicme://entries/{id}`
8+
or `epicme://tags/{id}`. This means clients can discover and read individual entries or
99
tags by their unique identifiers, just like accessing a file by its path.
1010

1111
Here's a dynamic "hello world" resource template example that reads names from a

exercises/03.resources/02.problem.template/src/resources.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1-
import { userInfo } from 'node:os'
21
// 💰 you'll use both of these in this exercise:
32
// import { invariant } from '@epic-web/invariant'
43
// import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
54
import { type EpicMeMCP } from './index.ts'
65

76
export async function initializeResources(agent: EpicMeMCP) {
87
agent.server.resource(
9-
'credits',
10-
'meta://credits',
11-
{
12-
description: 'Credits for the creators of the app',
13-
},
8+
'tags',
9+
'epicme://tags',
10+
{ description: 'All tags' },
1411
async (uri) => {
12+
const tags = await agent.db.getTags()
1513
return {
1614
contents: [
1715
{
18-
mimeType: 'text/plain',
19-
text: `This app was created by ${userInfo().username}`,
16+
mimeType: 'application/json',
17+
text: JSON.stringify(tags),
2018
uri: uri.toString(),
2119
},
2220
],
@@ -25,8 +23,8 @@ export async function initializeResources(agent: EpicMeMCP) {
2523
)
2624

2725
// 🐨 create two resources with a ResourceTemplate:
28-
// - entry - URI: entry://{id}
29-
// - tag - URI: tag://{id}
26+
// - entry - URI: epicme://entries/{id}
27+
// - tag - URI: epicme://tags/{id}
3028
// 🐨 each should have a list method that returns all the entries and tags (respectively)
3129
// 🐨 each should have a description
3230
// 🐨 each should have a callback that reads the entry or tag for the given id

exercises/03.resources/02.solution.template/src/resources.ts

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
import { userInfo } from 'node:os'
21
import { invariant } from '@epic-web/invariant'
32
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
43
import { type EpicMeMCP } from './index.ts'
54

65
export async function initializeResources(agent: EpicMeMCP) {
76
agent.server.resource(
8-
'credits',
9-
'meta://credits',
10-
{
11-
description: 'Credits for the creators of the app',
12-
},
7+
'tags',
8+
'epicme://tags',
9+
{ description: 'All tags' },
1310
async (uri) => {
11+
const tags = await agent.db.getTags()
1412
return {
1513
contents: [
1614
{
17-
mimeType: 'text/plain',
18-
text: `This app was created by ${userInfo().username}`,
15+
mimeType: 'application/json',
16+
text: JSON.stringify(tags),
1917
uri: uri.toString(),
2018
},
2119
],
@@ -24,28 +22,28 @@ export async function initializeResources(agent: EpicMeMCP) {
2422
)
2523

2624
agent.server.resource(
27-
'entry',
28-
new ResourceTemplate('entry://{id}', {
25+
'tag',
26+
new ResourceTemplate('epicme://tags/{id}', {
2927
list: async () => {
30-
const entries = await agent.db.getEntries()
28+
const tags = await agent.db.getTags()
3129
return {
32-
resources: entries.map((entry) => ({
33-
name: entry.title,
34-
uri: `entry://${entry.id}`,
30+
resources: tags.map((tag) => ({
31+
name: tag.name,
32+
uri: `epicme://tags/${tag.id}`,
3533
mimeType: 'application/json',
3634
})),
3735
}
3836
},
3937
}),
40-
{ description: 'A single entry' },
38+
{ description: 'A single tag' },
4139
async (uri, { id }) => {
42-
const entry = await agent.db.getEntry(Number(id))
43-
invariant(entry, `Entry with ID "${id}" not found`)
40+
const tag = await agent.db.getTag(Number(id))
41+
invariant(tag, `Tag with ID "${id}" not found`)
4442
return {
4543
contents: [
4644
{
4745
mimeType: 'application/json',
48-
text: JSON.stringify(entry),
46+
text: JSON.stringify(tag),
4947
uri: uri.toString(),
5048
},
5149
],
@@ -54,28 +52,28 @@ export async function initializeResources(agent: EpicMeMCP) {
5452
)
5553

5654
agent.server.resource(
57-
'tag',
58-
new ResourceTemplate('tag://{id}', {
55+
'entry',
56+
new ResourceTemplate('epicme://entries/{id}', {
5957
list: async () => {
60-
const tags = await agent.db.getTags()
58+
const entries = await agent.db.getEntries()
6159
return {
62-
resources: tags.map((tag) => ({
63-
name: tag.name,
64-
uri: `tag://${tag.id}`,
60+
resources: entries.map((entry) => ({
61+
name: entry.title,
62+
uri: `epicme://entries/${entry.id}`,
6563
mimeType: 'application/json',
6664
})),
6765
}
6866
},
6967
}),
70-
{ description: 'A single tag' },
68+
{ description: 'A single entry' },
7169
async (uri, { id }) => {
72-
const tag = await agent.db.getTag(Number(id))
73-
invariant(tag, `Tag with ID "${id}" not found`)
70+
const entry = await agent.db.getEntry(Number(id))
71+
invariant(entry, `Entry with ID "${id}" not found`)
7472
return {
7573
contents: [
7674
{
7775
mimeType: 'application/json',
78-
text: JSON.stringify(tag),
76+
text: JSON.stringify(entry),
7977
uri: uri.toString(),
8078
},
8179
],

exercises/03.resources/03.problem.embedded/src/resources.ts

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
import { userInfo } from 'node:os'
21
import { invariant } from '@epic-web/invariant'
32
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
43
import { type EpicMeMCP } from './index.ts'
54

65
export async function initializeResources(agent: EpicMeMCP) {
76
agent.server.resource(
8-
'credits',
9-
'meta://credits',
10-
{
11-
description: 'Credits for the creators of the app',
12-
},
7+
'tags',
8+
'epicme://tags',
9+
{ description: 'All tags' },
1310
async (uri) => {
11+
const tags = await agent.db.getTags()
1412
return {
1513
contents: [
1614
{
17-
mimeType: 'text/plain',
18-
text: `This app was created by ${userInfo().username}`,
15+
mimeType: 'application/json',
16+
text: JSON.stringify(tags),
1917
uri: uri.toString(),
2018
},
2119
],
@@ -24,28 +22,28 @@ export async function initializeResources(agent: EpicMeMCP) {
2422
)
2523

2624
agent.server.resource(
27-
'entry',
28-
new ResourceTemplate('entry://{id}', {
25+
'tag',
26+
new ResourceTemplate('epicme://tags/{id}', {
2927
list: async () => {
30-
const entries = await agent.db.getEntries()
28+
const tags = await agent.db.getTags()
3129
return {
32-
resources: entries.map((entry) => ({
33-
name: entry.title,
34-
uri: `entry://${entry.id}`,
30+
resources: tags.map((tag) => ({
31+
name: tag.name,
32+
uri: `epicme://tags/${tag.id}`,
3533
mimeType: 'application/json',
3634
})),
3735
}
3836
},
3937
}),
40-
{ description: 'A single entry' },
38+
{ description: 'A single tag' },
4139
async (uri, { id }) => {
42-
const entry = await agent.db.getEntry(Number(id))
43-
invariant(entry, `Entry with ID "${id}" not found`)
40+
const tag = await agent.db.getTag(Number(id))
41+
invariant(tag, `Tag with ID "${id}" not found`)
4442
return {
4543
contents: [
4644
{
4745
mimeType: 'application/json',
48-
text: JSON.stringify(entry),
46+
text: JSON.stringify(tag),
4947
uri: uri.toString(),
5048
},
5149
],
@@ -54,28 +52,28 @@ export async function initializeResources(agent: EpicMeMCP) {
5452
)
5553

5654
agent.server.resource(
57-
'tag',
58-
new ResourceTemplate('tag://{id}', {
55+
'entry',
56+
new ResourceTemplate('epicme://entries/{id}', {
5957
list: async () => {
60-
const tags = await agent.db.getTags()
58+
const entries = await agent.db.getEntries()
6159
return {
62-
resources: tags.map((tag) => ({
63-
name: tag.name,
64-
uri: `tag://${tag.id}`,
60+
resources: entries.map((entry) => ({
61+
name: entry.title,
62+
uri: `epicme://entries/${entry.id}`,
6563
mimeType: 'application/json',
6664
})),
6765
}
6866
},
6967
}),
70-
{ description: 'A single tag' },
68+
{ description: 'A single entry' },
7169
async (uri, { id }) => {
72-
const tag = await agent.db.getTag(Number(id))
73-
invariant(tag, `Tag with ID "${id}" not found`)
70+
const entry = await agent.db.getEntry(Number(id))
71+
invariant(entry, `Entry with ID "${id}" not found`)
7472
return {
7573
contents: [
7674
{
7775
mimeType: 'application/json',
78-
text: JSON.stringify(tag),
76+
text: JSON.stringify(entry),
7977
uri: uri.toString(),
8078
},
8179
],

exercises/03.resources/03.solution.embedded/src/resources.ts

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
import { userInfo } from 'node:os'
21
import { invariant } from '@epic-web/invariant'
32
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
43
import { type EpicMeMCP } from './index.ts'
54

65
export async function initializeResources(agent: EpicMeMCP) {
76
agent.server.resource(
8-
'credits',
9-
'meta://credits',
10-
{
11-
description: 'Credits for the creators of the app',
12-
},
7+
'tags',
8+
'epicme://tags',
9+
{ description: 'All tags' },
1310
async (uri) => {
11+
const tags = await agent.db.getTags()
1412
return {
1513
contents: [
1614
{
17-
mimeType: 'text/plain',
18-
text: `This app was created by ${userInfo().username}`,
15+
mimeType: 'application/json',
16+
text: JSON.stringify(tags),
1917
uri: uri.toString(),
2018
},
2119
],
@@ -24,28 +22,28 @@ export async function initializeResources(agent: EpicMeMCP) {
2422
)
2523

2624
agent.server.resource(
27-
'entry',
28-
new ResourceTemplate('entry://{id}', {
25+
'tag',
26+
new ResourceTemplate('epicme://tags/{id}', {
2927
list: async () => {
30-
const entries = await agent.db.getEntries()
28+
const tags = await agent.db.getTags()
3129
return {
32-
resources: entries.map((entry) => ({
33-
name: entry.title,
34-
uri: `entry://${entry.id}`,
30+
resources: tags.map((tag) => ({
31+
name: tag.name,
32+
uri: `epicme://tags/${tag.id}`,
3533
mimeType: 'application/json',
3634
})),
3735
}
3836
},
3937
}),
40-
{ description: 'A single entry' },
38+
{ description: 'A single tag' },
4139
async (uri, { id }) => {
42-
const entry = await agent.db.getEntry(Number(id))
43-
invariant(entry, `Entry with ID "${id}" not found`)
40+
const tag = await agent.db.getTag(Number(id))
41+
invariant(tag, `Tag with ID "${id}" not found`)
4442
return {
4543
contents: [
4644
{
4745
mimeType: 'application/json',
48-
text: JSON.stringify(entry),
46+
text: JSON.stringify(tag),
4947
uri: uri.toString(),
5048
},
5149
],
@@ -54,28 +52,28 @@ export async function initializeResources(agent: EpicMeMCP) {
5452
)
5553

5654
agent.server.resource(
57-
'tag',
58-
new ResourceTemplate('tag://{id}', {
55+
'entry',
56+
new ResourceTemplate('epicme://entries/{id}', {
5957
list: async () => {
60-
const tags = await agent.db.getTags()
58+
const entries = await agent.db.getEntries()
6159
return {
62-
resources: tags.map((tag) => ({
63-
name: tag.name,
64-
uri: `tag://${tag.id}`,
60+
resources: entries.map((entry) => ({
61+
name: entry.title,
62+
uri: `epicme://entries/${entry.id}`,
6563
mimeType: 'application/json',
6664
})),
6765
}
6866
},
6967
}),
70-
{ description: 'A single tag' },
68+
{ description: 'A single entry' },
7169
async (uri, { id }) => {
72-
const tag = await agent.db.getTag(Number(id))
73-
invariant(tag, `Tag with ID "${id}" not found`)
70+
const entry = await agent.db.getEntry(Number(id))
71+
invariant(entry, `Entry with ID "${id}" not found`)
7472
return {
7573
contents: [
7674
{
7775
mimeType: 'application/json',
78-
text: JSON.stringify(tag),
76+
text: JSON.stringify(entry),
7977
uri: uri.toString(),
8078
},
8179
],

0 commit comments

Comments
 (0)