@cyanheads/mcp-ts-core 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/README.md +2 -2
- package/dist/mcp-server/apps/appBuilders.d.ts +9 -1
- package/dist/mcp-server/apps/appBuilders.d.ts.map +1 -1
- package/dist/mcp-server/apps/appBuilders.js +64 -2
- package/dist/mcp-server/apps/appBuilders.js.map +1 -1
- package/dist/mcp-server/resources/utils/resourceDefinition.d.ts +16 -8
- package/dist/mcp-server/resources/utils/resourceDefinition.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceDefinition.js.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +11 -1
- package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
- package/package.json +3 -3
- package/skills/add-app-tool/SKILL.md +54 -32
- package/skills/add-prompt/SKILL.md +16 -11
- package/skills/add-resource/SKILL.md +16 -11
- package/skills/add-service/SKILL.md +47 -6
- package/skills/add-test/SKILL.md +23 -24
- package/skills/add-tool/SKILL.md +55 -13
- package/skills/api-testing/SKILL.md +56 -10
- package/skills/api-workers/SKILL.md +9 -7
- package/skills/devcheck/SKILL.md +20 -6
- package/skills/field-test/SKILL.md +17 -2
- package/skills/maintenance/SKILL.md +4 -2
- package/skills/migrate-mcp-ts-template/SKILL.md +14 -12
- package/skills/polish-docs-meta/SKILL.md +4 -4
- package/skills/setup/SKILL.md +9 -9
- package/templates/AGENTS.md +4 -0
- package/templates/CLAUDE.md +3 -0
- package/templates/src/mcp-server/resources/definitions/echo-app-ui.app-resource.ts +25 -4
package/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent Protocol
|
|
2
2
|
|
|
3
|
-
**Package:** `@cyanheads/mcp-ts-core` · **Version:** 0.3.
|
|
3
|
+
**Package:** `@cyanheads/mcp-ts-core` · **Version:** 0.3.4
|
|
4
4
|
**npm:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) · **Docker:** [ghcr.io/cyanheads/mcp-ts-core](https://ghcr.io/cyanheads/mcp-ts-core)
|
|
5
5
|
|
|
6
6
|
> **Developer note:** Never assume. Read related files and docs before making changes. Read full file content for context. Never edit a file before reading it.
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
<div align="center">
|
|
7
7
|
|
|
8
|
-
[](./CHANGELOG.md) [](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-11-25/changelog.mdx) [](https://modelcontextprotocol.io/) [](./LICENSE)
|
|
9
9
|
|
|
10
10
|
[](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
@@ -163,7 +163,7 @@ See [CLAUDE.md](CLAUDE.md) for the full configuration reference.
|
|
|
163
163
|
| `resource(uriTemplate, options)` | Define a resource with `handler(params, ctx)` |
|
|
164
164
|
| `prompt(name, options)` | Define a prompt with `generate(args)` |
|
|
165
165
|
| `appTool(name, options)` | Define an MCP Apps tool with auto-populated `_meta.ui` |
|
|
166
|
-
| `appResource(uriTemplate, options)` | Define an MCP Apps HTML resource with correct MIME type |
|
|
166
|
+
| `appResource(uriTemplate, options)` | Define an MCP Apps HTML resource with the correct MIME type and `_meta.ui` mirroring for read content |
|
|
167
167
|
|
|
168
168
|
### Context
|
|
169
169
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @fileoverview Convenience builders for MCP Apps — `appTool()` and `appResource()`.
|
|
3
3
|
* Wraps the standard `tool()` and `resource()` builders with MCP Apps-specific
|
|
4
4
|
* defaults: auto-populates `_meta.ui.resourceUri`, sets the correct MIME type,
|
|
5
|
-
*
|
|
5
|
+
* handles the compat key (`ui/resourceUri`) required by some hosts, and mirrors
|
|
6
|
+
* app resource `_meta.ui` into `resources/read` content items.
|
|
6
7
|
* @module src/mcp-server/apps/appBuilders
|
|
7
8
|
*/
|
|
8
9
|
import type { ZodObject, ZodRawShape } from 'zod';
|
|
@@ -53,6 +54,8 @@ type AppResourceOptions<TParams extends ZodObject<ZodRawShape>, TOutput extends
|
|
|
53
54
|
* Creates an MCP Apps resource definition. Wraps `resource()` with:
|
|
54
55
|
* - `mimeType` defaulting to `text/html;profile=mcp-app`
|
|
55
56
|
* - `annotations.audience` defaulting to `['user']`
|
|
57
|
+
* - `_meta.ui` preserved on the definition and mirrored into `resources/read`
|
|
58
|
+
* content items so hosts receive the same CSP/permission metadata at read time
|
|
56
59
|
*
|
|
57
60
|
* The `uriTemplate` should use the `ui://` scheme.
|
|
58
61
|
*
|
|
@@ -64,6 +67,11 @@ type AppResourceOptions<TParams extends ZodObject<ZodRawShape>, TOutput extends
|
|
|
64
67
|
* name: 'my-app-ui',
|
|
65
68
|
* description: 'Interactive UI for my_app_tool.',
|
|
66
69
|
* params: z.object({}).describe('No parameters.'),
|
|
70
|
+
* _meta: {
|
|
71
|
+
* ui: {
|
|
72
|
+
* csp: { resourceDomains: ['https://cdn.example.com'] },
|
|
73
|
+
* },
|
|
74
|
+
* },
|
|
67
75
|
* handler(_params, ctx) {
|
|
68
76
|
* return '<html>...</html>';
|
|
69
77
|
* },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appBuilders.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/apps/appBuilders.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"appBuilders.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/apps/appBuilders.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAElD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oDAAoD,CAAC;AAE7F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAGjF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,8BAA8B,CAAC;AAuFlE,wFAAwF;AACxF,KAAK,cAAc,CACjB,MAAM,SAAS,SAAS,CAAC,WAAW,CAAC,EACrC,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,IACpC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,GAAG;IAC5D;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CACrB,MAAM,SAAS,SAAS,CAAC,WAAW,CAAC,EACrC,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,EACtC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzF;AAMD,0FAA0F;AAC1F,KAAK,kBAAkB,CACrB,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,EACtC,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,GAAG,SAAS,GAAG,SAAS,IAC5D,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC,GAAG;IAC3E,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CACzB,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,EACtC,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,GAAG,SAAS,GAAG,SAAS,EAE9D,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,GAC5C,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAetC"}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* @fileoverview Convenience builders for MCP Apps — `appTool()` and `appResource()`.
|
|
3
3
|
* Wraps the standard `tool()` and `resource()` builders with MCP Apps-specific
|
|
4
4
|
* defaults: auto-populates `_meta.ui.resourceUri`, sets the correct MIME type,
|
|
5
|
-
*
|
|
5
|
+
* handles the compat key (`ui/resourceUri`) required by some hosts, and mirrors
|
|
6
|
+
* app resource `_meta.ui` into `resources/read` content items.
|
|
6
7
|
* @module src/mcp-server/apps/appBuilders
|
|
7
8
|
*/
|
|
8
9
|
import { resource } from '../../mcp-server/resources/utils/resourceDefinition.js';
|
|
@@ -18,6 +19,56 @@ export const APP_RESOURCE_MIME_TYPE = 'text/html;profile=mcp-app';
|
|
|
18
19
|
* Matches `RESOURCE_URI_META_KEY` from `@modelcontextprotocol/ext-apps/server`.
|
|
19
20
|
*/
|
|
20
21
|
const RESOURCE_URI_META_KEY = 'ui/resourceUri';
|
|
22
|
+
function isPlainObject(value) {
|
|
23
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
function isJsonMimeType(mimeType) {
|
|
26
|
+
const normalizedMimeType = mimeType.split(';', 1)[0]?.trim().toLowerCase() ?? '';
|
|
27
|
+
return normalizedMimeType === 'application/json' || normalizedMimeType.endsWith('+json');
|
|
28
|
+
}
|
|
29
|
+
function formatResourceText(result, mimeType) {
|
|
30
|
+
return typeof result === 'string' && !isJsonMimeType(mimeType)
|
|
31
|
+
? result
|
|
32
|
+
: JSON.stringify(result, null, 2);
|
|
33
|
+
}
|
|
34
|
+
function mergeNestedRecords(base, override) {
|
|
35
|
+
const merged = { ...base };
|
|
36
|
+
for (const [key, value] of Object.entries(override)) {
|
|
37
|
+
const existing = merged[key];
|
|
38
|
+
merged[key] =
|
|
39
|
+
isPlainObject(existing) && isPlainObject(value) ? mergeNestedRecords(existing, value) : value;
|
|
40
|
+
}
|
|
41
|
+
return merged;
|
|
42
|
+
}
|
|
43
|
+
function mirrorUiMetaIntoContents(contents, defaultUiMeta) {
|
|
44
|
+
return contents.map((content) => {
|
|
45
|
+
const contentMeta = isPlainObject(content._meta) ? content._meta : {};
|
|
46
|
+
const contentUiMeta = contentMeta.ui;
|
|
47
|
+
return {
|
|
48
|
+
...content,
|
|
49
|
+
_meta: {
|
|
50
|
+
...contentMeta,
|
|
51
|
+
ui: isPlainObject(contentUiMeta)
|
|
52
|
+
? mergeNestedRecords(defaultUiMeta, contentUiMeta)
|
|
53
|
+
: (contentUiMeta ?? defaultUiMeta),
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function createAppResourceFormat(format, defaultUiMeta) {
|
|
59
|
+
if (!defaultUiMeta)
|
|
60
|
+
return format;
|
|
61
|
+
return (result, meta) => {
|
|
62
|
+
const contents = format?.(result, meta) ?? [
|
|
63
|
+
{
|
|
64
|
+
uri: meta.uri.href,
|
|
65
|
+
text: formatResourceText(result, meta.mimeType),
|
|
66
|
+
mimeType: meta.mimeType,
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
return mirrorUiMetaIntoContents(contents, defaultUiMeta);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
21
72
|
/**
|
|
22
73
|
* Creates an MCP Apps tool definition. Wraps `tool()` with:
|
|
23
74
|
* - `_meta.ui.resourceUri` set automatically
|
|
@@ -57,6 +108,8 @@ export function appTool(name, options) {
|
|
|
57
108
|
* Creates an MCP Apps resource definition. Wraps `resource()` with:
|
|
58
109
|
* - `mimeType` defaulting to `text/html;profile=mcp-app`
|
|
59
110
|
* - `annotations.audience` defaulting to `['user']`
|
|
111
|
+
* - `_meta.ui` preserved on the definition and mirrored into `resources/read`
|
|
112
|
+
* content items so hosts receive the same CSP/permission metadata at read time
|
|
60
113
|
*
|
|
61
114
|
* The `uriTemplate` should use the `ui://` scheme.
|
|
62
115
|
*
|
|
@@ -68,6 +121,11 @@ export function appTool(name, options) {
|
|
|
68
121
|
* name: 'my-app-ui',
|
|
69
122
|
* description: 'Interactive UI for my_app_tool.',
|
|
70
123
|
* params: z.object({}).describe('No parameters.'),
|
|
124
|
+
* _meta: {
|
|
125
|
+
* ui: {
|
|
126
|
+
* csp: { resourceDomains: ['https://cdn.example.com'] },
|
|
127
|
+
* },
|
|
128
|
+
* },
|
|
71
129
|
* handler(_params, ctx) {
|
|
72
130
|
* return '<html>...</html>';
|
|
73
131
|
* },
|
|
@@ -75,9 +133,13 @@ export function appTool(name, options) {
|
|
|
75
133
|
* ```
|
|
76
134
|
*/
|
|
77
135
|
export function appResource(uriTemplate, options) {
|
|
78
|
-
const { mimeType, annotations, ...rest } = options;
|
|
136
|
+
const { mimeType, annotations, _meta, format, ...rest } = options;
|
|
137
|
+
const defaultUiMeta = isPlainObject(_meta?.ui) ? _meta.ui : undefined;
|
|
138
|
+
const appResourceFormat = createAppResourceFormat(format, defaultUiMeta);
|
|
79
139
|
return resource(uriTemplate, {
|
|
80
140
|
...rest,
|
|
141
|
+
...(_meta && { _meta }),
|
|
142
|
+
...(appResourceFormat && { format: appResourceFormat }),
|
|
81
143
|
mimeType: mimeType ?? APP_RESOURCE_MIME_TYPE,
|
|
82
144
|
annotations: {
|
|
83
145
|
audience: ['user'],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appBuilders.js","sourceRoot":"","sources":["../../../src/mcp-server/apps/appBuilders.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"appBuilders.js","sourceRoot":"","sources":["../../../src/mcp-server/apps/appBuilders.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,15 +30,22 @@ export type ListExtra = RequestHandlerExtra<ServerRequest, ServerNotification>;
|
|
|
30
30
|
*/
|
|
31
31
|
export interface ResourceDefinition<TParams extends ZodObject<ZodRawShape> = ZodObject<ZodRawShape>, TOutput extends ZodObject<ZodRawShape> | undefined = undefined> {
|
|
32
32
|
/**
|
|
33
|
-
* Protocol-level metadata for the resource.
|
|
34
|
-
* For MCP Apps UI resources,
|
|
33
|
+
* Protocol-level metadata for the resource registration itself.
|
|
34
|
+
* For plain `resource()` MCP Apps UI resources, host-consumed UI metadata that
|
|
35
|
+
* must travel with `resources/read` content (for example `_meta.ui.csp` or
|
|
36
|
+
* permissions) should be attached to the returned content item from `format()`:
|
|
35
37
|
* ```ts
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* format: (html, meta) => [{
|
|
39
|
+
* uri: meta.uri.href,
|
|
40
|
+
* text: html as string,
|
|
41
|
+
* mimeType: meta.mimeType,
|
|
42
|
+
* _meta: {
|
|
43
|
+
* ui: {
|
|
44
|
+
* csp: { resourceDomains: ['https://cdn.example.com'] },
|
|
45
|
+
* permissions: { microphone: {} },
|
|
46
|
+
* },
|
|
40
47
|
* },
|
|
41
|
-
* }
|
|
48
|
+
* }]
|
|
42
49
|
* ```
|
|
43
50
|
*/
|
|
44
51
|
_meta?: Record<string, unknown>;
|
|
@@ -55,7 +62,8 @@ export interface ResourceDefinition<TParams extends ZodObject<ZodRawShape> = Zod
|
|
|
55
62
|
}[];
|
|
56
63
|
/**
|
|
57
64
|
* Optional formatter mapping output to ReadResourceResult contents.
|
|
58
|
-
* If omitted, a default
|
|
65
|
+
* If omitted, a default formatter is used: string results pass through for
|
|
66
|
+
* non-JSON MIME types, and JSON MIME types stringify all values.
|
|
59
67
|
*/
|
|
60
68
|
format?: (result: unknown, meta: {
|
|
61
69
|
uri: URL;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resourceDefinition.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceDefinition.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AACxF,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACd,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,CAAC,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC;IACpC,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iDAAiD;AACjD,MAAM,MAAM,SAAS,GAAG,mBAAmB,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;AAE/E;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CACjC,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,EAC/D,OAAO,SAAS,SAAS,CAAC,WAAW,CAAC,GAAG,SAAS,GAAG,SAAS;IAE9D
|
|
1
|
+
{"version":3,"file":"resourceDefinition.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceDefinition.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resourceDefinition.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceDefinition.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"resourceDefinition.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceDefinition.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA8GH,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,QAAQ,CAItB,WAAmB,EACnB,OAAkE;IAElE,OAAO,EAAE,WAAW,EAAE,GAAG,OAAO,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resourceHandlerFactory.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceHandlerFactory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AACxF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iDAAiD,CAAC;AACjF,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACd,MAAM,oCAAoC,CAAC;AAK5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAC;AAEhG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAGvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAQzD,KAAK,QAAQ,GAAG,mBAAmB,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;AAOvE,qEAAqE;AACrE,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB,CAAC,EAAE,MAAM,IAAI,CAAC;IACvC,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,cAAc,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"resourceHandlerFactory.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceHandlerFactory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8CAA8C,CAAC;AACxF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iDAAiD,CAAC;AACjF,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACd,MAAM,oCAAoC,CAAC;AAK5C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAC;AAEhG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAGvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAQzD,KAAK,QAAQ,GAAG,mBAAmB,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;AAOvE,qEAAqE;AACrE,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB,CAAC,EAAE,MAAM,IAAI,CAAC;IACvC,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,cAAc,CAAC;CACzB;AAqDD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,qBAAqB,EAC1B,QAAQ,EAAE,8BAA8B,GACvC,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAyElF"}
|
|
@@ -12,11 +12,21 @@ import { requestContextService } from '../../../utils/internal/requestContext.js
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// Default formatter
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
|
+
function isJsonMimeType(mimeType) {
|
|
16
|
+
const normalizedMimeType = mimeType.split(';', 1)[0]?.trim().toLowerCase() ?? '';
|
|
17
|
+
return normalizedMimeType === 'application/json' || normalizedMimeType.endsWith('+json');
|
|
18
|
+
}
|
|
19
|
+
function formatResourceText(result, mimeType) {
|
|
20
|
+
return typeof result === 'string' && !isJsonMimeType(mimeType)
|
|
21
|
+
? result
|
|
22
|
+
: JSON.stringify(result, null, 2);
|
|
23
|
+
}
|
|
15
24
|
function defaultResponseFormatter(result, meta) {
|
|
25
|
+
const text = formatResourceText(result, meta.mimeType);
|
|
16
26
|
return [
|
|
17
27
|
{
|
|
18
28
|
uri: meta.uri.href,
|
|
19
|
-
text
|
|
29
|
+
text,
|
|
20
30
|
mimeType: meta.mimeType,
|
|
21
31
|
},
|
|
22
32
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resourceHandlerFactory.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceHandlerFactory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AAEnF,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAE9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAqB3E,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,SAAS,
|
|
1
|
+
{"version":3,"file":"resourceHandlerFactory.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/utils/resourceHandlerFactory.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/mcp-ts-core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"mcpName": "io.github.cyanheads/mcp-ts-core",
|
|
5
5
|
"description": "Agent-native TypeScript framework for building MCP servers. Build tools, not infrastructure. Declarative definitions with auth, multi-backend storage, OpenTelemetry, and first-class support for Node.js and Cloudflare Workers.",
|
|
6
6
|
"main": "dist/core/index.js",
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
},
|
|
158
158
|
"devDependencies": {
|
|
159
159
|
"@biomejs/biome": "2.4.10",
|
|
160
|
-
"@cloudflare/workers-types": "^4.
|
|
160
|
+
"@cloudflare/workers-types": "^4.20260409.1",
|
|
161
161
|
"@hono/otel": "^1.1.1",
|
|
162
162
|
"@opentelemetry/instrumentation-http": "^0.214.0",
|
|
163
163
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.214.0",
|
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
"typescript": "^6.0.2",
|
|
201
201
|
"unpdf": "^1.4.0",
|
|
202
202
|
"validator": "^13.15.35",
|
|
203
|
-
"vite": "8.0.
|
|
203
|
+
"vite": "8.0.8",
|
|
204
204
|
"vitest": "^4.1.3"
|
|
205
205
|
},
|
|
206
206
|
"keywords": [
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Scaffold an MCP App tool + UI resource pair. Use when the user asks to add a tool with interactive UI, create an MCP App, or build a visual/interactive tool.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
@@ -28,7 +28,7 @@ For the full API, Context interface, and error codes, read:
|
|
|
28
28
|
2. **Choose a URI** — convention: `ui://{{tool-name}}/app.html`
|
|
29
29
|
3. **Create the app tool** at `src/mcp-server/tools/definitions/{{tool-name}}.app-tool.ts`
|
|
30
30
|
4. **Create the app resource** at `src/mcp-server/resources/definitions/{{tool-name}}-ui.app-resource.ts`
|
|
31
|
-
5. **Register both** in
|
|
31
|
+
5. **Register both** in the project's existing `createApp()` arrays (directly in `src/index.ts` for fresh scaffolds, or via barrels if the repo already has them)
|
|
32
32
|
6. **Run `bun run devcheck`** — the linter validates `_meta.ui` and cross-checks tool/resource pairing
|
|
33
33
|
7. **Smoke-test** with `bun run dev:stdio` or `dev:http`
|
|
34
34
|
|
|
@@ -64,11 +64,11 @@ export const {{TOOL_EXPORT}} = appTool('{{tool_name}}', {
|
|
|
64
64
|
|
|
65
65
|
// format() serves dual purpose for app tools:
|
|
66
66
|
// 1. First text block: JSON for the UI (app.ontoolresult parses it)
|
|
67
|
-
// 2. Subsequent blocks: human-readable fallback for non-app hosts and LLM context
|
|
67
|
+
// 2. Subsequent blocks: human-readable, content-complete fallback for non-app hosts and LLM context
|
|
68
68
|
format(result) {
|
|
69
69
|
return [
|
|
70
70
|
{ type: 'text', text: JSON.stringify(result) },
|
|
71
|
-
{ type: 'text', text: '/* human-readable summary */' },
|
|
71
|
+
{ type: 'text', text: '/* human-readable summary with all LLM-needed fields */' },
|
|
72
72
|
];
|
|
73
73
|
},
|
|
74
74
|
});
|
|
@@ -98,10 +98,29 @@ const APP_HTML = `<!DOCTYPE html>
|
|
|
98
98
|
<!-- your UI markup -->
|
|
99
99
|
|
|
100
100
|
<script type="module">
|
|
101
|
-
|
|
101
|
+
// Prefer a bundled or inlined SDK for the final shipped HTML. Leaving a live
|
|
102
|
+
// CDN import in the served ui:// resource is not the recommended default.
|
|
103
|
+
import {
|
|
104
|
+
App,
|
|
105
|
+
applyDocumentTheme,
|
|
106
|
+
applyHostFonts,
|
|
107
|
+
applyHostStyleVariables,
|
|
108
|
+
} from "https://unpkg.com/@modelcontextprotocol/ext-apps@1/app-with-deps";
|
|
102
109
|
|
|
103
110
|
const app = new App({ name: "{{TOOL_TITLE}}", version: "1.0.0" });
|
|
104
111
|
|
|
112
|
+
function applyHostContext(hostContext) {
|
|
113
|
+
if (hostContext?.theme) {
|
|
114
|
+
applyDocumentTheme(hostContext.theme);
|
|
115
|
+
}
|
|
116
|
+
if (hostContext?.styles?.variables) {
|
|
117
|
+
applyHostStyleVariables(hostContext.styles.variables);
|
|
118
|
+
}
|
|
119
|
+
if (hostContext?.styles?.css?.fonts) {
|
|
120
|
+
applyHostFonts(hostContext.styles.css.fonts);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
105
124
|
// Receive initial tool result from the host
|
|
106
125
|
app.ontoolresult = (result) => {
|
|
107
126
|
const text = result.content?.find(c => c.type === "text")?.text;
|
|
@@ -109,6 +128,7 @@ const APP_HTML = `<!DOCTYPE html>
|
|
|
109
128
|
const data = JSON.parse(text);
|
|
110
129
|
// render data into the DOM
|
|
111
130
|
};
|
|
131
|
+
app.onhostcontextchanged = applyHostContext;
|
|
112
132
|
|
|
113
133
|
// Proactively call tools from the UI
|
|
114
134
|
document.getElementById("action-btn").addEventListener("click", async () => {
|
|
@@ -119,7 +139,10 @@ const APP_HTML = `<!DOCTYPE html>
|
|
|
119
139
|
// handle result
|
|
120
140
|
});
|
|
121
141
|
|
|
122
|
-
|
|
142
|
+
app.connect().then(() => {
|
|
143
|
+
const hostContext = app.getHostContext();
|
|
144
|
+
if (hostContext) applyHostContext(hostContext);
|
|
145
|
+
});
|
|
123
146
|
</script>
|
|
124
147
|
</body>
|
|
125
148
|
</html>`;
|
|
@@ -128,14 +151,13 @@ export const {{RESOURCE_EXPORT}} = appResource('ui://{{tool-name}}/app.html', {
|
|
|
128
151
|
name: '{{tool-name}}-ui',
|
|
129
152
|
title: '{{TOOL_TITLE}} UI',
|
|
130
153
|
description: 'Interactive HTML app for {{tool_name}}.',
|
|
131
|
-
|
|
154
|
+
params: ParamsSchema,
|
|
155
|
+
// auth: ['resource:{{tool-name}}-ui:read'],
|
|
132
156
|
_meta: {
|
|
133
157
|
ui: {
|
|
134
158
|
csp: { resourceDomains: ['https://unpkg.com'] },
|
|
135
159
|
},
|
|
136
160
|
},
|
|
137
|
-
params: ParamsSchema,
|
|
138
|
-
// auth: ['resource:{{tool-name}}-ui:read'],
|
|
139
161
|
|
|
140
162
|
handler(_params, ctx) {
|
|
141
163
|
ctx.log.debug('Serving app UI.', { resourceUri: ctx.uri?.href });
|
|
@@ -156,39 +178,39 @@ export const {{RESOURCE_EXPORT}} = appResource('ui://{{tool-name}}/app.html', {
|
|
|
156
178
|
|
|
157
179
|
## UI Design Notes
|
|
158
180
|
|
|
159
|
-
- **Bundling:**
|
|
160
|
-
- **Client-side SDK:**
|
|
161
|
-
- **CSP:** MCP Apps iframes run under deny-by-default CSP.
|
|
162
|
-
- **format() for
|
|
181
|
+
- **Bundling:** Prefer Vite + `vite-plugin-singlefile` for any UI that uses `@modelcontextprotocol/ext-apps`. The served `ui://` HTML should ideally be self-contained. The inline template literal pattern is fine for zero-dependency UIs or when you inline the SDK yourself.
|
|
182
|
+
- **Client-side SDK:** Author against `@modelcontextprotocol/ext-apps`, but ship a bundled or inlined artifact when possible. Avoid relying on a live CDN import as the default final pattern for portable host compatibility.
|
|
183
|
+
- **CSP:** MCP Apps iframes run under deny-by-default CSP. With `appResource()`, put `_meta.ui.csp.resourceDomains` on the definition and the builder will mirror it into returned `resources/read` content items. With plain `resource()`, you still need to attach `_meta.ui` yourself in `format()`.
|
|
184
|
+
- **App resource `format()`:** `appResource()` already preserves raw HTML for the default app MIME type and mirrors definition `_meta.ui` into content items. Add a custom `format()` only when you need extra per-read metadata or non-default content shaping.
|
|
185
|
+
- **format() for app tools:** The first `text` content block is typically JSON that the UI parses via `ontoolresult`. Additional blocks provide a human-readable fallback that non-app hosts and LLMs consume. Do not rely on the JSON block alone for model-visible detail; the fallback blocks still need to render the fields the LLM must reason about.
|
|
163
186
|
|
|
164
|
-
##
|
|
187
|
+
## Registration
|
|
165
188
|
|
|
166
189
|
```typescript
|
|
167
|
-
// src/
|
|
168
|
-
import {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
]
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
export const allResourceDefinitions = [
|
|
179
|
-
// ... existing resources,
|
|
180
|
-
{{RESOURCE_EXPORT}},
|
|
181
|
-
];
|
|
190
|
+
// src/index.ts (fresh scaffold default)
|
|
191
|
+
import { createApp } from '@cyanheads/mcp-ts-core';
|
|
192
|
+
import { {{TOOL_EXPORT}} } from './mcp-server/tools/definitions/{{tool-name}}.app-tool.js';
|
|
193
|
+
import { {{RESOURCE_EXPORT}} } from './mcp-server/resources/definitions/{{tool-name}}-ui.app-resource.js';
|
|
194
|
+
|
|
195
|
+
await createApp({
|
|
196
|
+
tools: [{{TOOL_EXPORT}}],
|
|
197
|
+
resources: [{{RESOURCE_EXPORT}}],
|
|
198
|
+
prompts: [/* existing prompts */],
|
|
199
|
+
});
|
|
182
200
|
```
|
|
183
201
|
|
|
202
|
+
If the repo already uses `definitions/index.ts` barrels, update those instead of changing the registration pattern.
|
|
203
|
+
|
|
184
204
|
## Checklist
|
|
185
205
|
|
|
186
206
|
- [ ] App tool created at `src/mcp-server/tools/definitions/{{tool-name}}.app-tool.ts` using `appTool()`
|
|
187
207
|
- [ ] App resource created at `src/mcp-server/resources/definitions/{{tool-name}}-ui.app-resource.ts` using `appResource()`
|
|
188
208
|
- [ ] `resourceUri` matches between tool and resource (`ui://{{tool-name}}/app.html`)
|
|
189
209
|
- [ ] Zod schemas: all fields have `.describe()`, only JSON-Schema-serializable types
|
|
190
|
-
- [ ] `format()` renders JSON first block (for UI) + human-readable blocks (for non-app hosts)
|
|
191
|
-
- [ ]
|
|
192
|
-
- [ ]
|
|
210
|
+
- [ ] `format()` renders JSON first block (for UI) + human-readable, content-complete fallback blocks (for non-app hosts and LLMs)
|
|
211
|
+
- [ ] App resource `_meta.ui.csp` covers any external iframe dependencies, or a custom `format()` adds equivalent per-read metadata
|
|
212
|
+
- [ ] UI bundles or inlines the client SDK for the shipped HTML, and handles `app.ontoolresult`
|
|
213
|
+
- [ ] UI applies host context updates via `app.onhostcontextchanged`
|
|
214
|
+
- [ ] Both registered in the project's existing `createApp()` arrays (directly or via barrels)
|
|
193
215
|
- [ ] `bun run devcheck` passes (linter validates `_meta.ui` and tool/resource pairing)
|
|
194
216
|
- [ ] Smoke-tested with `bun run dev:stdio` or `dev:http`
|
|
@@ -4,14 +4,14 @@ description: >
|
|
|
4
4
|
Scaffold a new MCP prompt template. Use when the user asks to add a prompt, create a reusable message template, or define a prompt for LLM interactions.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.1"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Context
|
|
13
13
|
|
|
14
|
-
Prompts use the `prompt()` builder from `@cyanheads/mcp-ts-core`. Each prompt lives in `src/mcp-server/prompts/definitions/` with a `.prompt.ts` suffix and is registered in
|
|
14
|
+
Prompts use the `prompt()` builder from `@cyanheads/mcp-ts-core`. Each prompt lives in `src/mcp-server/prompts/definitions/` with a `.prompt.ts` suffix and is registered into `createApp()` in `src/index.ts`. Some repos later add `definitions/index.ts` barrels; match the project's current pattern.
|
|
15
15
|
|
|
16
16
|
Prompts are pure message templates — no `Context`, no auth, no side effects.
|
|
17
17
|
|
|
@@ -23,7 +23,7 @@ For the full `prompt()` API, read:
|
|
|
23
23
|
|
|
24
24
|
1. **Ask the user** for the prompt's name, purpose, and arguments
|
|
25
25
|
2. **Create the file** at `src/mcp-server/prompts/definitions/{{prompt-name}}.prompt.ts`
|
|
26
|
-
3. **Register** the prompt in `src/
|
|
26
|
+
3. **Register** the prompt in the project's existing `createApp()` prompt list (directly in `src/index.ts` for fresh scaffolds, or via a barrel if the repo already has one)
|
|
27
27
|
4. **Run `bun run devcheck`** to verify
|
|
28
28
|
|
|
29
29
|
## Template
|
|
@@ -74,17 +74,22 @@ generate: (args) => [
|
|
|
74
74
|
],
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
###
|
|
77
|
+
### Registration
|
|
78
78
|
|
|
79
79
|
```typescript
|
|
80
|
-
// src/
|
|
81
|
-
import {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
]
|
|
80
|
+
// src/index.ts (fresh scaffold default)
|
|
81
|
+
import { createApp } from '@cyanheads/mcp-ts-core';
|
|
82
|
+
import { {{PROMPT_EXPORT}} } from './mcp-server/prompts/definitions/{{prompt-name}}.prompt.js';
|
|
83
|
+
|
|
84
|
+
await createApp({
|
|
85
|
+
tools: [/* existing tools */],
|
|
86
|
+
resources: [/* existing resources */],
|
|
87
|
+
prompts: [{{PROMPT_EXPORT}}],
|
|
88
|
+
});
|
|
86
89
|
```
|
|
87
90
|
|
|
91
|
+
If the repo already uses `src/mcp-server/prompts/definitions/index.ts`, update that barrel instead.
|
|
92
|
+
|
|
88
93
|
## Checklist
|
|
89
94
|
|
|
90
95
|
- [ ] File created at `src/mcp-server/prompts/definitions/{{prompt-name}}.prompt.ts`
|
|
@@ -92,5 +97,5 @@ export const allPromptDefinitions = [
|
|
|
92
97
|
- [ ] JSDoc `@fileoverview` and `@module` header present
|
|
93
98
|
- [ ] `generate` function returns valid message array
|
|
94
99
|
- [ ] No side effects — prompts are pure templates
|
|
95
|
-
- [ ] Registered in `
|
|
100
|
+
- [ ] Registered in the project's existing `createApp()` prompt list (directly or via barrel)
|
|
96
101
|
- [ ] `bun run devcheck` passes
|
|
@@ -4,14 +4,14 @@ description: >
|
|
|
4
4
|
Scaffold a new MCP resource definition. Use when the user asks to add a resource, expose data via URI, or create a readable endpoint.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: reference
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Context
|
|
13
13
|
|
|
14
|
-
Resources use the `resource()` builder from `@cyanheads/mcp-ts-core`. Each resource lives in `src/mcp-server/resources/definitions/` with a `.resource.ts` suffix and is registered in
|
|
14
|
+
Resources use the `resource()` builder from `@cyanheads/mcp-ts-core`. Each resource lives in `src/mcp-server/resources/definitions/` with a `.resource.ts` suffix and is registered into `createApp()` in `src/index.ts`. Some repos later add `definitions/index.ts` barrels; follow the pattern already used by the project.
|
|
15
15
|
|
|
16
16
|
**Tool coverage.** Not all MCP clients expose resources — many are tool-only (Claude Code, Cursor, most chat UIs). Before adding a resource, verify the same data is reachable via the tool surface — either through a dedicated tool, included in another tool's output, or bundled into a broader tool. A resource whose data has no tool path is invisible to a large share of agents.
|
|
17
17
|
|
|
@@ -24,7 +24,7 @@ For the full `resource()` API, pagination utilities, and `Context` interface, re
|
|
|
24
24
|
1. **Ask the user** for the resource's URI template, purpose, and data shape
|
|
25
25
|
2. **Design the URI** — use `{paramName}` for path parameters (e.g., `myscheme://{itemId}/data`)
|
|
26
26
|
3. **Create the file** at `src/mcp-server/resources/definitions/{{resource-name}}.resource.ts`
|
|
27
|
-
4. **Register** the resource in `src/
|
|
27
|
+
4. **Register** the resource in the project's existing `createApp()` resource list (directly in `src/index.ts` for fresh scaffolds, or via a barrel if the repo already has one)
|
|
28
28
|
5. **Run `bun run devcheck`** to verify
|
|
29
29
|
6. **Smoke-test** with `bun run dev:stdio` or `dev:http`
|
|
30
30
|
|
|
@@ -93,17 +93,22 @@ async handler(params, ctx) {
|
|
|
93
93
|
},
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
###
|
|
96
|
+
### Registration
|
|
97
97
|
|
|
98
98
|
```typescript
|
|
99
|
-
// src/
|
|
100
|
-
import {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
]
|
|
99
|
+
// src/index.ts (fresh scaffold default)
|
|
100
|
+
import { createApp } from '@cyanheads/mcp-ts-core';
|
|
101
|
+
import { {{RESOURCE_EXPORT}} } from './mcp-server/resources/definitions/{{resource-name}}.resource.js';
|
|
102
|
+
|
|
103
|
+
await createApp({
|
|
104
|
+
tools: [/* existing tools */],
|
|
105
|
+
resources: [{{RESOURCE_EXPORT}}],
|
|
106
|
+
prompts: [/* existing prompts */],
|
|
107
|
+
});
|
|
105
108
|
```
|
|
106
109
|
|
|
110
|
+
If the repo already uses `src/mcp-server/resources/definitions/index.ts`, update that barrel instead of changing the registration style.
|
|
111
|
+
|
|
107
112
|
## Checklist
|
|
108
113
|
|
|
109
114
|
- [ ] File created at `src/mcp-server/resources/definitions/{{resource-name}}.resource.ts`
|
|
@@ -114,6 +119,6 @@ export const allResourceDefinitions = [
|
|
|
114
119
|
- [ ] Data is reachable via the tool surface (dedicated tool, another tool's output, or not needed for tool-only agents)
|
|
115
120
|
- [ ] `list()` function provided if the resource is discoverable
|
|
116
121
|
- [ ] Pagination used for large result sets (`extractCursor`/`paginateArray`)
|
|
117
|
-
- [ ] Registered in `
|
|
122
|
+
- [ ] Registered in the project's existing `createApp()` resource list (directly or via barrel)
|
|
118
123
|
- [ ] `bun run devcheck` passes
|
|
119
124
|
- [ ] Smoke-tested with `bun run dev:stdio` or `dev:http`
|