@cyanheads/mcp-ts-core 0.6.10 → 0.6.12
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 +1 -1
- package/biome.json +1 -1
- package/changelog/0.6.x/0.6.11.md +23 -0
- package/changelog/0.6.x/0.6.12.md +15 -0
- package/dist/logs/combined.log +4 -4
- package/dist/logs/error.log +4 -4
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/parsing/htmlExtractor.d.ts +146 -0
- package/dist/utils/parsing/htmlExtractor.d.ts.map +1 -0
- package/dist/utils/parsing/htmlExtractor.js +171 -0
- package/dist/utils/parsing/htmlExtractor.js.map +1 -0
- package/dist/utils/parsing/index.d.ts +1 -0
- package/dist/utils/parsing/index.d.ts.map +1 -1
- package/dist/utils/parsing/index.js +1 -0
- package/dist/utils/parsing/index.js.map +1 -1
- package/package.json +15 -5
- package/skills/field-test/SKILL.md +205 -82
- package/skills/report-issue-framework/SKILL.md +54 -4
- package/skills/report-issue-local/SKILL.md +60 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/mcp-ts-core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.12",
|
|
4
4
|
"mcpName": "io.github.cyanheads/mcp-ts-core",
|
|
5
5
|
"description": "Agent-native TypeScript framework for building MCP servers. Declarative definitions with auth, multi-backend storage, OpenTelemetry, and first-class support for Bun/Node/Cloudflare Workers.",
|
|
6
6
|
"main": "dist/core/index.js",
|
|
@@ -159,12 +159,12 @@
|
|
|
159
159
|
"yaml": "1.10.3"
|
|
160
160
|
},
|
|
161
161
|
"devDependencies": {
|
|
162
|
-
"@biomejs/biome": "2.4.
|
|
162
|
+
"@biomejs/biome": "2.4.13",
|
|
163
163
|
"@cloudflare/workers-types": "^4.20260423.1",
|
|
164
164
|
"@hono/otel": "^1.1.1",
|
|
165
|
-
"@opentelemetry/instrumentation-http": "^0.215.0",
|
|
166
165
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.215.0",
|
|
167
166
|
"@opentelemetry/exporter-trace-otlp-http": "^0.215.0",
|
|
167
|
+
"@opentelemetry/instrumentation-http": "^0.215.0",
|
|
168
168
|
"@opentelemetry/instrumentation-pino": "^0.61.0",
|
|
169
169
|
"@opentelemetry/resources": "^2.7.0",
|
|
170
170
|
"@opentelemetry/sdk-metrics": "^2.7.0",
|
|
@@ -183,20 +183,22 @@
|
|
|
183
183
|
"bun-types": "^1.3.13",
|
|
184
184
|
"chrono-node": "^2.9.0",
|
|
185
185
|
"clipboardy": "^5.3.1",
|
|
186
|
+
"defuddle": "^0.18.1",
|
|
186
187
|
"depcheck": "^1.4.7",
|
|
187
188
|
"diff": "^9.0.0",
|
|
188
189
|
"execa": "^9.6.1",
|
|
189
190
|
"fast-check": "^4.7.0",
|
|
190
|
-
"js-yaml": "^4.1.1",
|
|
191
191
|
"ignore": "^7.0.5",
|
|
192
|
+
"js-yaml": "^4.1.1",
|
|
193
|
+
"linkedom": "^0.18.12",
|
|
192
194
|
"node-cron": "^4.2.1",
|
|
193
195
|
"openai": "^6.34.0",
|
|
194
196
|
"papaparse": "^5.5.3",
|
|
195
197
|
"partial-json": "^0.1.7",
|
|
196
198
|
"pdf-lib": "^1.17.1",
|
|
197
199
|
"pino-pretty": "^13.1.3",
|
|
198
|
-
"sanitize-html": "^2.17.3",
|
|
199
200
|
"repomix": "^1.13.1",
|
|
201
|
+
"sanitize-html": "^2.17.3",
|
|
200
202
|
"tsc-alias": "^1.8.16",
|
|
201
203
|
"typedoc": "^0.28.19",
|
|
202
204
|
"typescript": "^6.0.3",
|
|
@@ -278,9 +280,11 @@
|
|
|
278
280
|
"@opentelemetry/semantic-conventions": "^1.40.0",
|
|
279
281
|
"@supabase/supabase-js": "^2.103.3",
|
|
280
282
|
"chrono-node": "^2.9.0",
|
|
283
|
+
"defuddle": "^0.18.1",
|
|
281
284
|
"diff": "latest",
|
|
282
285
|
"fast-xml-parser": "latest",
|
|
283
286
|
"js-yaml": "^4.1.1",
|
|
287
|
+
"linkedom": "^0.18.12",
|
|
284
288
|
"node-cron": "^4.2.1",
|
|
285
289
|
"openai": "^6.34.0",
|
|
286
290
|
"papaparse": "^5.5.3",
|
|
@@ -327,6 +331,9 @@
|
|
|
327
331
|
"chrono-node": {
|
|
328
332
|
"optional": true
|
|
329
333
|
},
|
|
334
|
+
"defuddle": {
|
|
335
|
+
"optional": true
|
|
336
|
+
},
|
|
330
337
|
"diff": {
|
|
331
338
|
"optional": true
|
|
332
339
|
},
|
|
@@ -336,6 +343,9 @@
|
|
|
336
343
|
"js-yaml": {
|
|
337
344
|
"optional": true
|
|
338
345
|
},
|
|
346
|
+
"linkedom": {
|
|
347
|
+
"optional": true
|
|
348
|
+
},
|
|
339
349
|
"node-cron": {
|
|
340
350
|
"optional": true
|
|
341
351
|
},
|
|
@@ -1,127 +1,250 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: field-test
|
|
3
3
|
description: >
|
|
4
|
-
Exercise tools, resources, and prompts
|
|
4
|
+
Exercise tools, resources, and prompts against a live HTTP server via MCP JSON-RPC over curl. Starts the server, surfaces the catalog, runs real and adversarial inputs, and produces a tight report with concrete findings and numbered follow-up options. Use after adding or modifying definitions, or when the user asks to test, try out, or verify their MCP surface.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "
|
|
7
|
+
version: "2.0"
|
|
8
8
|
audience: external
|
|
9
9
|
type: debug
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
## Context
|
|
13
13
|
|
|
14
|
-
Unit tests (`add-test` skill) verify handler logic with mocked context. Field testing
|
|
14
|
+
Unit tests (`add-test` skill) verify handler logic with mocked context. Field testing exercises the real HTTP transport with real JSON-RPC: starts the server, calls `initialize`, surfaces the catalog, runs inputs, and checks what a client actually sees. It catches what unit tests miss — awkward input shapes, unhelpful errors, missing format output, drift between `structuredContent` and `content[]`, edge-case surprises.
|
|
15
15
|
|
|
16
|
-
**Actively
|
|
16
|
+
**Actively call the tools. Don't read code and guess.**
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
20
|
## Steps
|
|
21
21
|
|
|
22
|
-
### 1.
|
|
22
|
+
### 1. Start the server
|
|
23
|
+
|
|
24
|
+
Write the helper to `/tmp/mcp-field-test.sh` once, then source it in every subsequent Bash call. Helper keeps PID / URL / session id in `/tmp/mcp-field-test.env` so state survives across tool invocations.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cat > /tmp/mcp-field-test.sh <<'HELPER_EOF'
|
|
28
|
+
#!/bin/bash
|
|
29
|
+
# Field-test helper: manage an MCP HTTP server + JSON-RPC session across shell calls.
|
|
30
|
+
STATE_FILE="/tmp/mcp-field-test.env"
|
|
31
|
+
[ -f "$STATE_FILE" ] && . "$STATE_FILE"
|
|
32
|
+
|
|
33
|
+
mcp_start() {
|
|
34
|
+
local dir="${1:-$PWD}"
|
|
35
|
+
echo "building $dir ..."
|
|
36
|
+
(cd "$dir" && bun run rebuild) >/tmp/mcp-build.log 2>&1 \
|
|
37
|
+
|| { echo "BUILD FAILED — see /tmp/mcp-build.log"; return 1; }
|
|
38
|
+
echo "starting server ..."
|
|
39
|
+
(cd "$dir" && bun run start:http) >/tmp/mcp-server.log 2>&1 &
|
|
40
|
+
local pid=$!
|
|
41
|
+
local line=""
|
|
42
|
+
for _ in $(seq 1 40); do
|
|
43
|
+
line=$(grep -Eo 'listening at http://[^" ]+/mcp' /tmp/mcp-server.log | head -1)
|
|
44
|
+
[ -n "$line" ] && break
|
|
45
|
+
sleep 0.25
|
|
46
|
+
done
|
|
47
|
+
if [ -z "$line" ]; then
|
|
48
|
+
echo "server failed to start — see /tmp/mcp-server.log"
|
|
49
|
+
kill "$pid" 2>/dev/null
|
|
50
|
+
return 1
|
|
51
|
+
fi
|
|
52
|
+
local url="${line#listening at }"
|
|
53
|
+
local port; port=$(echo "$url" | sed -E 's|.*:([0-9]+)/.*|\1|')
|
|
54
|
+
cat > "$STATE_FILE" <<EOF
|
|
55
|
+
export MCP_PID=$pid
|
|
56
|
+
export MCP_URL=$url
|
|
57
|
+
export MCP_PORT=$port
|
|
58
|
+
EOF
|
|
59
|
+
. "$STATE_FILE"
|
|
60
|
+
echo "ready pid=$pid url=$url"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
mcp_init() {
|
|
64
|
+
[ -z "$MCP_URL" ] && { echo "run mcp_start first"; return 1; }
|
|
65
|
+
local hdr="/tmp/mcp-init-headers.txt"
|
|
66
|
+
curl -sS -D "$hdr" -X POST "$MCP_URL" \
|
|
67
|
+
-H "Content-Type: application/json" \
|
|
68
|
+
-H "Accept: application/json, text/event-stream" \
|
|
69
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"field-test","version":"2.0"}}}' >/dev/null
|
|
70
|
+
local sid; sid=$(grep -i '^mcp-session-id:' "$hdr" | awk '{print $2}' | tr -d '\r\n')
|
|
71
|
+
[ -z "$sid" ] && { echo "no session id returned"; return 1; }
|
|
72
|
+
cat > "$STATE_FILE" <<EOF
|
|
73
|
+
export MCP_PID=$MCP_PID
|
|
74
|
+
export MCP_URL=$MCP_URL
|
|
75
|
+
export MCP_PORT=$MCP_PORT
|
|
76
|
+
export MCP_SID=$sid
|
|
77
|
+
EOF
|
|
78
|
+
. "$STATE_FILE"
|
|
79
|
+
curl -sS -X POST "$MCP_URL" \
|
|
80
|
+
-H "Content-Type: application/json" \
|
|
81
|
+
-H "Accept: application/json, text/event-stream" \
|
|
82
|
+
-H "Mcp-Session-Id: $sid" \
|
|
83
|
+
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}' >/dev/null
|
|
84
|
+
echo "session=$sid"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Usage: mcp_call METHOD [JSON_PARAMS]
|
|
88
|
+
# Prints the JSON-RPC response (SSE framing stripped). Pipe to `jq`.
|
|
89
|
+
mcp_call() {
|
|
90
|
+
[ -z "$MCP_SID" ] && { echo "run mcp_init first"; return 1; }
|
|
91
|
+
local method="$1"; local params="${2:-}"
|
|
92
|
+
local body
|
|
93
|
+
if [ -z "$params" ]; then
|
|
94
|
+
body=$(printf '{"jsonrpc":"2.0","id":%d,"method":"%s"}' "$RANDOM" "$method")
|
|
95
|
+
else
|
|
96
|
+
body=$(printf '{"jsonrpc":"2.0","id":%d,"method":"%s","params":%s}' "$RANDOM" "$method" "$params")
|
|
97
|
+
fi
|
|
98
|
+
curl -sS -X POST "$MCP_URL" \
|
|
99
|
+
-H "Content-Type: application/json" \
|
|
100
|
+
-H "Accept: application/json, text/event-stream" \
|
|
101
|
+
-H "Mcp-Session-Id: $MCP_SID" \
|
|
102
|
+
-d "$body" | sed -n 's/^data: //p'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
mcp_stop() {
|
|
106
|
+
[ -n "$MCP_PID" ] && kill "$MCP_PID" 2>/dev/null
|
|
107
|
+
rm -f "$STATE_FILE"
|
|
108
|
+
echo "stopped"
|
|
109
|
+
}
|
|
110
|
+
HELPER_EOF
|
|
111
|
+
|
|
112
|
+
. /tmp/mcp-field-test.sh
|
|
113
|
+
mcp_start /absolute/path/to/server # replace with the target server
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Notes**
|
|
117
|
+
|
|
118
|
+
- `MCP_HTTP_PORT` is a *starting* port — the server auto-increments if taken. Helper parses the real URL from the log (`HTTP transport listening at ...`).
|
|
119
|
+
- If `bun run rebuild` fails, stop. Don't field-test broken code — fix the build first.
|
|
120
|
+
- If a server is already listening on the project's port (`lsof -i :<port>`), confirm with the user before killing it; it may be their own session.
|
|
121
|
+
|
|
122
|
+
### 2. Initialize the session
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
. /tmp/mcp-field-test.sh
|
|
126
|
+
mcp_init
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Runs `initialize`, captures the session id, sends `notifications/initialized`.
|
|
130
|
+
|
|
131
|
+
### 3. Surface the catalog
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
. /tmp/mcp-field-test.sh
|
|
135
|
+
mcp_call tools/list | jq '.result.tools[] | {name, description, inputSchema}'
|
|
136
|
+
mcp_call resources/list | jq '.result.resources[] | {uri, name, mimeType}'
|
|
137
|
+
mcp_call prompts/list | jq '.result.prompts[] | {name, description, arguments}'
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Present a compact catalog to the user: each definition's name + 1-line description. Flag vague or missing descriptions as you go — those feed into the report. Use this to build the test plan.
|
|
141
|
+
|
|
142
|
+
### 4. Plan the test pass
|
|
143
|
+
|
|
144
|
+
**Budget.** Don't run every category against every definition — the cross-product is infeasible. Apply the **universal battery** to everything; apply **situational categories** only when the definition triggers them.
|
|
145
|
+
|
|
146
|
+
**Universal battery — run on every tool**
|
|
147
|
+
|
|
148
|
+
| Category | What to verify |
|
|
149
|
+
|:---------|:---------------|
|
|
150
|
+
| Happy path | One realistic input. Output shape matches schema. `content[]` text reads clearly to a human. |
|
|
151
|
+
| `structuredContent` ↔ `content[]` parity | Every field in `structuredContent` is surfaced in the text. Parity gap = client-specific blindness. |
|
|
152
|
+
| Input error | One invalid input (wrong type or missing required). Error text says *what*, *why*, *how to fix*. |
|
|
153
|
+
|
|
154
|
+
**Situational — add only when triggered**
|
|
155
|
+
|
|
156
|
+
| Trigger (look in input schema or `annotations`) | Add category |
|
|
157
|
+
|:------------------------------------------------|:-------------|
|
|
158
|
+
| `include` / `fields` / `expand` / `view` / `projection` parameter | Field selection: non-default value renders requested fields |
|
|
159
|
+
| Array return with `query` / `filter` inputs | Empty result: does response explain *why* (echo criteria, suggest broadening)? |
|
|
160
|
+
| Batch / bulk input (arrays of IDs, multi-item ops) | Partial success: mix valid + invalid items |
|
|
161
|
+
| `annotations.readOnlyHint: true` | Confirm no mutation happened |
|
|
162
|
+
| `annotations.idempotentHint: true` | Call twice with same input — safe? |
|
|
163
|
+
| Hits external API / live upstream | One call that exercises upstream; note rate-limit / timeout / transient-failure behavior |
|
|
164
|
+
| Chained with other tools (search → detail → act) | Run one representative chain end-to-end; does each step return the IDs/cursors the next needs? |
|
|
165
|
+
| `cursor` / `offset` / `limit` params | Pagination: second page, end-of-list |
|
|
23
166
|
|
|
24
|
-
|
|
167
|
+
**Resources.** Happy path, not-found URI, `list` if defined, pagination if used.
|
|
168
|
+
**Prompts.** Happy path, defaults omitted, skim message quality.
|
|
25
169
|
|
|
26
|
-
|
|
170
|
+
**Sampling for large servers.** If more than 15 tools, run the universal battery on all, but pick roughly 30–40% for situational testing. Weight toward: write-shaped tools, complex schemas, external deps. List which ones you skipped in the report.
|
|
27
171
|
|
|
28
|
-
|
|
172
|
+
**Auth & external state.**
|
|
29
173
|
|
|
30
|
-
|
|
174
|
+
- If a tool needs real API keys and they're not set, note `skipped — requires $VAR` and move on. Don't fabricate inputs.
|
|
175
|
+
- Tools that write to real external systems (third-party APIs, shared DBs): confirm with the user before running, or use a dry-run input if one exists.
|
|
31
176
|
|
|
32
|
-
|
|
177
|
+
### 5. Execute
|
|
33
178
|
|
|
34
|
-
|
|
179
|
+
Use `TaskCreate` — one task per definition. Mark complete as you go. Don't batch.
|
|
35
180
|
|
|
36
|
-
|
|
37
|
-
|:---------|:-------------|
|
|
38
|
-
| **Happy path** | Realistic input that should succeed. Verify output shape matches the output schema. Verify format function produces sensible content blocks. |
|
|
39
|
-
| **`structuredContent` parity** | The `format-parity` lint rule already asserts every terminal field in the output schema appears in `format()`'s rendered text (via sentinel injection at startup). Field testing layers real-data checks on top: are values rendered accurately (not just their labels)? Do conditional-render branches in `format()` still render every field when specific values are present? Does the content look right to a human reading the LLM's view? |
|
|
40
|
-
| **Variations** | Different valid input combinations — optional fields omitted, optional fields included, different enum values, min/max boundaries. |
|
|
41
|
-
| **Field selection / projection** | For tools with `fields`, `include`, `expand`, `view`, or similar parameters, call the tool with non-default selections. Verify the handler returns the requested fields and `format()` renders each requested field rather than a hardcoded summary subset. |
|
|
42
|
-
| **Edge cases** | Empty strings, zero values, very long inputs, special characters, Unicode. |
|
|
43
|
-
| **Error paths** | Missing required fields, wrong types, nonexistent IDs, inputs that should trigger domain errors. Verify errors are clear and actionable — they should name what went wrong, why, and what to do next. |
|
|
44
|
-
| **Empty results** | Inputs that match nothing. Verify the response explains *why* (echoes criteria, suggests broadening) rather than returning a bare empty array. |
|
|
45
|
-
| **Partial success** | For tools that operate on multiple items, test cases where some succeed and some fail. Verify both outcomes are reported — not just the successes. |
|
|
46
|
-
| **Annotations** | Review tool `annotations` (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) against actual behavior. If a tool is marked read-only, verify it does not mutate state. If it is marked idempotent, verify retries with the same input are safe. If it is marked open-world false, verify it is not silently depending on live external systems. |
|
|
47
|
-
| **Workflow chaining** | For servers with multi-step workflows, execute 1-2 representative chains end-to-end. Example: search → detail → follow-up action. Verify each step returns the IDs, cursors, URIs, tokens, or state needed for the next step without guessing. |
|
|
48
|
-
| **Response quality** | Inspect successful responses for: (1) chaining IDs needed for follow-up calls, (2) operational metadata (counts, applied filters, truncation notices), (3) filtering transparency (if anything was excluded, does the response say what and how to include it?), (4) reasonable response size (not dumping unbounded data into context). See the `add-tool` skill's **Tool Response Design** section for the full set of patterns. |
|
|
49
|
-
| **Resilience** | For tools backed by external APIs or slow subsystems, test or explicitly note rate-limit, timeout, and transient-failure behavior. Verify retries/backoff happen where intended, or at minimum that the error message clearly tells the user whether to retry, wait, or change input. |
|
|
50
|
-
| **Descriptions** | Read every field's `.describe()` — would a user/LLM understand what to provide? Flag vague or missing descriptions. |
|
|
181
|
+
For each call, capture: input sent, response (trim huge payloads to files), whether `isError: true` appeared, anything surprising (slow response, parity drift, unhelpful text, crash).
|
|
51
182
|
|
|
52
|
-
|
|
183
|
+
**Interpreting responses**
|
|
53
184
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
| **List** | Call `list` if defined. Verify returned resources have names and valid URIs. |
|
|
58
|
-
| **Not found** | URI with nonexistent params. Verify a clear error, not a crash. |
|
|
59
|
-
| **Pagination** | If the resource uses `extractCursor`/`paginateArray`, test with varying limits and cursors. |
|
|
185
|
+
- Tool domain errors return `{result: {content: [...], isError: true}}` — they live in `result`, not `error`. Check `isError`, not the JSON-RPC error field.
|
|
186
|
+
- JSON-RPC `error` only appears for protocol issues (bad session, malformed envelope, unknown method).
|
|
187
|
+
- `mcp_call` already strips SSE framing. Pipe to `jq` for readability.
|
|
60
188
|
|
|
61
|
-
|
|
189
|
+
### 6. Tear down
|
|
62
190
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
| **Content quality** | Read the generated messages — are they clear, well-structured prompts? |
|
|
191
|
+
```bash
|
|
192
|
+
. /tmp/mcp-field-test.sh
|
|
193
|
+
mcp_stop
|
|
194
|
+
```
|
|
68
195
|
|
|
69
|
-
|
|
196
|
+
Kills the background server, clears state. Do this *before* writing the report so nothing leaks into the next session.
|
|
70
197
|
|
|
71
|
-
|
|
198
|
+
### 7. Report
|
|
72
199
|
|
|
73
|
-
|
|
200
|
+
Three sections. Tight. The user should be able to skim the summary, read details only for what matters, and act on numbered options.
|
|
74
201
|
|
|
75
|
-
|
|
202
|
+
#### Summary (1 paragraph)
|
|
76
203
|
|
|
77
|
-
|
|
204
|
+
One paragraph. How many definitions exercised, how many passed clean, how many have issues, and the single most important finding. No tables, no lists.
|
|
78
205
|
|
|
79
|
-
|
|
80
|
-
|:-----------|:-----|:-------|:-------|
|
|
81
|
-
| `acme_search_items` | tool | pass | — |
|
|
82
|
-
| `acme_get_item` | tool | issues | Error message unhelpful for missing ID |
|
|
83
|
-
| `item://` | resource | fail | Crashes on nonexistent ID |
|
|
206
|
+
#### Findings
|
|
84
207
|
|
|
85
|
-
|
|
208
|
+
Only include definitions with issues. Group by severity. Each finding is 2–4 lines unless it genuinely needs more.
|
|
86
209
|
|
|
87
|
-
|
|
210
|
+
| Severity | Meaning |
|
|
211
|
+
|:---------|:--------|
|
|
212
|
+
| **bug** | Broken: crash, wrong output, `isError: true` on valid input, data loss, schema violation |
|
|
213
|
+
| **ux** | Works but degrades the user/LLM experience: vague description, unhelpful error text, missing `format()`, parity drift, annotation mismatches behavior |
|
|
214
|
+
| **nit** | Polish: phrasing, inconsistent tone, minor doc gaps |
|
|
88
215
|
|
|
89
|
-
|
|
90
|
-
- **Severity** — `bug` (broken behavior), `ux` (works but confusing/unhelpful), `nit` (minor polish)
|
|
91
|
-
- **Recommendation** — specific fix suggestion
|
|
216
|
+
Format:
|
|
92
217
|
|
|
93
|
-
|
|
218
|
+
```
|
|
219
|
+
**<tool_name> — <bug|ux|nit>**
|
|
220
|
+
Input: `<short input>` → <what happened>
|
|
221
|
+
Expected: <what should happen>
|
|
222
|
+
Fix: <one sentence>
|
|
223
|
+
```
|
|
94
224
|
|
|
95
|
-
|
|
225
|
+
#### Options
|
|
96
226
|
|
|
97
|
-
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
- Performance observations (unexpectedly slow responses)
|
|
227
|
+
Numbered, actionable, cherry-pickable. Each item maps to a concrete change.
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
1. Fix empty-result message in `pubmed_search_articles` — echo criteria (finding #2)
|
|
231
|
+
2. Add `format()` to `pubmed_lookup_mesh` — currently returns raw JSON (finding #5)
|
|
232
|
+
3. Tighten `ids` description in `pubmed_fetch_articles` — silent on PMID vs DOI (finding #8)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
End with:
|
|
236
|
+
|
|
237
|
+
> Pick by number (e.g. "do 1, 3, 5" or "expand on 2").
|
|
109
238
|
|
|
110
239
|
---
|
|
111
240
|
|
|
112
241
|
## Checklist
|
|
113
242
|
|
|
114
|
-
- [ ]
|
|
115
|
-
- [ ]
|
|
116
|
-
- [ ]
|
|
117
|
-
- [ ]
|
|
118
|
-
- [ ]
|
|
119
|
-
- [ ]
|
|
120
|
-
- [ ]
|
|
121
|
-
- [ ]
|
|
122
|
-
- [ ] Tool annotations reviewed against actual behavior
|
|
123
|
-
- [ ] Representative multi-step workflows exercised where applicable
|
|
124
|
-
- [ ] External API resilience reviewed where applicable (rate limits, timeouts, transient failures)
|
|
125
|
-
- [ ] Descriptions reviewed for completeness and accuracy
|
|
126
|
-
- [ ] Format functions verified (or absence noted)
|
|
127
|
-
- [ ] Summary report presented to user
|
|
243
|
+
- [ ] Server built and started; real port parsed from log
|
|
244
|
+
- [ ] Session initialized; `notifications/initialized` sent
|
|
245
|
+
- [ ] Catalog surfaced and presented
|
|
246
|
+
- [ ] Universal battery run on every definition
|
|
247
|
+
- [ ] Situational categories applied only when triggered
|
|
248
|
+
- [ ] External-state / auth-gated tools handled explicitly (run, skip, or confirm)
|
|
249
|
+
- [ ] Server stopped; state file removed
|
|
250
|
+
- [ ] Report: summary paragraph → grouped findings → numbered options
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
File a bug or feature request against @cyanheads/mcp-ts-core when you hit a framework issue. Use when a builder, utility, context method, or config behaves contrary to the documented API — not for server-specific application bugs.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -20,6 +20,8 @@ You've isolated a problem to `@cyanheads/mcp-ts-core` itself — not your server
|
|
|
20
20
|
- Type exports are incorrect or missing (compile error on documented usage)
|
|
21
21
|
- The definition linter (`bun run lint:mcp`) produces false positives or misses real violations
|
|
22
22
|
|
|
23
|
+
For general `gh` CLI workflows outside issue filing (PRs, workflows, API access), see the `github-cli` skill.
|
|
24
|
+
|
|
23
25
|
## Before Filing
|
|
24
26
|
|
|
25
27
|
1. **Confirm framework version** — `bun pm ls @cyanheads/mcp-ts-core` or check `node_modules/@cyanheads/mcp-ts-core/package.json`
|
|
@@ -31,6 +33,20 @@ You've isolated a problem to `@cyanheads/mcp-ts-core` itself — not your server
|
|
|
31
33
|
gh issue list -R cyanheads/mcp-ts-core --search "your error message or keyword"
|
|
32
34
|
```
|
|
33
35
|
|
|
36
|
+
## Writing Well-Structured Issues
|
|
37
|
+
|
|
38
|
+
Good issues are scannable, concrete, and self-contained. These patterns apply to both bugs and features — the guidance targets any prose block (Description, Additional context, feature proposals).
|
|
39
|
+
|
|
40
|
+
- **Lead with specifics.** Name the tool, function, module, or symptom. "Currently `createApp()` throws `ConfigurationError` when `MCP_HTTP_PORT` is set to `0`" beats "There's a problem with the config." A reader should know what's broken or missing before the end of the first sentence.
|
|
41
|
+
- **Embed library/service links on first mention.** `[Hono](https://hono.dev/)`, `[linkedom](https://github.com/WebReflection/linkedom)`. Link to the canonical repo or homepage so readers can verify the dependency and reach docs in one click.
|
|
42
|
+
- **Use `owner/repo#N` for cross-repo issue references.** GitHub auto-renders them as linked references (e.g. `cyanheads/pubmed-mcp-server#34`). Bare `#N` only works for same-repo issues.
|
|
43
|
+
- **Add a `Related: #N` line** near the top when the issue grows from prior context (discussions, other issues, PRs). Makes provenance clickable.
|
|
44
|
+
- **Lead design sections with a philosophy sentence.** Bold a short principle before the tradeoff details — e.g. "Philosophy: **fail fast on config errors, degrade gracefully on runtime errors.**" Establishes the lens for the rest of the section.
|
|
45
|
+
- **Prefer Markdown tables for comparisons.** When showing options, tiers, strategies, or tradeoffs — tables are the highest-density format for scanning N rows × M attributes.
|
|
46
|
+
- **Separate `### Scope` from `### Out of scope`.** The latter is as important as the former — it pre-empts scope-creep debates in comments and signals you've thought about the boundaries.
|
|
47
|
+
- **Use `Depends on: owner/repo#N`** to declare ordering explicitly when implementation is blocked on another issue landing first.
|
|
48
|
+
- **Skip collaborator-framing sign-offs.** Lines like "Happy to open a PR", "let me know if you'd like", "willing to contribute", "if that's the preferred flow" read as noise. A PR link beats an offer; if you're the maintainer filing against your own repo, the offer is redundant. End the body at the last substantive point.
|
|
49
|
+
|
|
34
50
|
## Redact Before Posting
|
|
35
51
|
|
|
36
52
|
GitHub issues are **public**. Do not include secrets, credentials, API keys, or tokens. Redact sensitive values from env vars, headers, and logs before submitting. Replace with obvious placeholders: `REDACTED`, `sk-...REDACTED`. Do not rely on partial masking — partial keys can still be exploited.
|
|
@@ -174,14 +190,20 @@ gh issue create -R cyanheads/mcp-ts-core --template "Feature Request" --web
|
|
|
174
190
|
|
|
175
191
|
### CLI (non-interactive)
|
|
176
192
|
|
|
193
|
+
Template below demonstrates the richer structure. Omit sections you don't need — simple requests don't require Flow / Design / Dependencies blocks.
|
|
194
|
+
|
|
177
195
|
````bash
|
|
178
196
|
gh issue create -R cyanheads/mcp-ts-core \
|
|
179
197
|
--title "feat(scope): concise description" \
|
|
180
198
|
--label "enhancement" \
|
|
181
199
|
--body "$(cat <<'ISSUE'
|
|
182
|
-
|
|
200
|
+
Concrete statement of what's currently missing or broken in the framework. Name the specific builder, utility, context method, or config field. Two or three sentences — the reader should know the gap before the end of the paragraph.
|
|
183
201
|
|
|
184
|
-
|
|
202
|
+
Related: #N
|
|
203
|
+
|
|
204
|
+
## Proposal
|
|
205
|
+
|
|
206
|
+
What you want the framework to do, in one paragraph. Link external libraries on first mention: [lib name](https://github.com/owner/repo). Include a short justification — what this gives us that we don't have today.
|
|
185
207
|
|
|
186
208
|
### Proposed API
|
|
187
209
|
|
|
@@ -194,9 +216,37 @@ const result = await withRetry(() => fetchExternal(url), {
|
|
|
194
216
|
});
|
|
195
217
|
```
|
|
196
218
|
|
|
219
|
+
### Flow (optional)
|
|
220
|
+
|
|
221
|
+
Ordered steps — e.g. `trigger → resolve → fetch → degrade`. Useful when the change spans multiple phases or fallbacks.
|
|
222
|
+
|
|
223
|
+
### Design / Tradeoffs (optional)
|
|
224
|
+
|
|
225
|
+
Philosophy: **one-line principle in bold.**
|
|
226
|
+
|
|
227
|
+
| Option | Strengths | Weaknesses |
|
|
228
|
+
|:---|:---|:---|
|
|
229
|
+
| A | ... | ... |
|
|
230
|
+
| B | ... | ... |
|
|
231
|
+
|
|
232
|
+
### Scope
|
|
233
|
+
|
|
234
|
+
- Files or modules touched
|
|
235
|
+
- New exports, env vars, or config keys
|
|
236
|
+
- Tier (Tier 1 core / Tier 2 standard / Tier 3 optional peer dep)
|
|
237
|
+
|
|
238
|
+
### Out of scope
|
|
239
|
+
|
|
240
|
+
- What we're deliberately not doing
|
|
241
|
+
- Adjacent work that belongs in a separate issue
|
|
242
|
+
|
|
243
|
+
### Dependencies (optional)
|
|
244
|
+
|
|
245
|
+
- Depends on: owner/repo#N
|
|
246
|
+
|
|
197
247
|
### Alternatives considered
|
|
198
248
|
|
|
199
|
-
What you tried or
|
|
249
|
+
What you tried or evaluated instead, and why it didn't fit.
|
|
200
250
|
ISSUE
|
|
201
251
|
)"
|
|
202
252
|
````
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
File a bug or feature request against this MCP server's own repo. Use for server-specific issues — tool logic, service integrations, config problems, or domain bugs that aren't caused by the framework.
|
|
5
5
|
metadata:
|
|
6
6
|
author: cyanheads
|
|
7
|
-
version: "1.
|
|
7
|
+
version: "1.2"
|
|
8
8
|
audience: external
|
|
9
9
|
type: workflow
|
|
10
10
|
---
|
|
@@ -22,6 +22,8 @@ The bug is in this server's code, not in `@cyanheads/mcp-ts-core`. Typical trigg
|
|
|
22
22
|
|
|
23
23
|
**If the issue is in the framework itself** (builders, Context, utilities, type exports, linter), use `report-issue-framework` instead.
|
|
24
24
|
|
|
25
|
+
For general `gh` CLI workflows outside issue filing (PRs, workflows, API access), see the `github-cli` skill.
|
|
26
|
+
|
|
25
27
|
## Before Filing
|
|
26
28
|
|
|
27
29
|
1. **Identify the repo**:
|
|
@@ -40,6 +42,20 @@ gh issue list --search "your error message or keyword"
|
|
|
40
42
|
|
|
41
43
|
4. **Check logs** — review `ctx.log` output and any framework telemetry for clues. If running HTTP, check the response body for structured error details.
|
|
42
44
|
|
|
45
|
+
## Writing Well-Structured Issues
|
|
46
|
+
|
|
47
|
+
Good issues are scannable, concrete, and self-contained. These patterns apply to both bugs and features — the guidance targets any prose block (Description, Additional context, feature proposals).
|
|
48
|
+
|
|
49
|
+
- **Lead with specifics.** Name the tool, service, resource, or symptom. "Currently `search_docs` returns an empty array for queries containing `&`" beats "Search is broken." A reader should know what's wrong before the end of the first sentence.
|
|
50
|
+
- **Embed library/service links on first mention.** `[Hono](https://hono.dev/)`, `[Supabase](https://supabase.com/)`. Link to the canonical repo or homepage so readers can verify the dependency and reach docs in one click.
|
|
51
|
+
- **Use `owner/repo#N` for cross-repo issue references.** GitHub auto-renders them as linked references (e.g. `cyanheads/mcp-ts-core#46`). Bare `#N` only works for same-repo issues — useful when the bug depends on or relates to a framework issue.
|
|
52
|
+
- **Add a `Related: #N` line** near the top when the issue grows from prior context (discussions, other issues, PRs). Makes provenance clickable.
|
|
53
|
+
- **Lead design sections with a philosophy sentence.** Bold a short principle before the tradeoff details — e.g. "Philosophy: **return best-effort data, don't fail the tool call on parsing edge cases.**" Establishes the lens for the rest of the section.
|
|
54
|
+
- **Prefer Markdown tables for comparisons.** When showing options, data sources, strategies, or tradeoffs — tables are the highest-density format for scanning N rows × M attributes.
|
|
55
|
+
- **Separate `### Scope` from `### Out of scope`.** The latter is as important as the former — it pre-empts scope-creep debates in comments and signals you've thought about the boundaries.
|
|
56
|
+
- **Use `Depends on: owner/repo#N`** to declare ordering explicitly when implementation is blocked on an upstream framework change or another issue landing first.
|
|
57
|
+
- **Skip collaborator-framing sign-offs.** Lines like "Happy to open a PR", "let me know if you'd like", "willing to contribute", "if that's the preferred flow" read as noise. A PR link beats an offer; if you're the maintainer filing against your own repo, the offer is redundant. End the body at the last substantive point.
|
|
58
|
+
|
|
43
59
|
## Redact Before Posting
|
|
44
60
|
|
|
45
61
|
GitHub issues are **public**. Do not include secrets, credentials, API keys, or tokens. Redact sensitive values from env vars, headers, and logs before submitting. Replace with obvious placeholders: `REDACTED`, `sk-...REDACTED`. Do not rely on partial masking — partial keys can still be exploited.
|
|
@@ -158,22 +174,61 @@ gh issue create --template "Feature Request" --web
|
|
|
158
174
|
|
|
159
175
|
### CLI (non-interactive)
|
|
160
176
|
|
|
177
|
+
Template below demonstrates the richer structure. Omit sections you don't need — simple requests don't require Flow / Design / Dependencies blocks.
|
|
178
|
+
|
|
161
179
|
````bash
|
|
162
180
|
gh issue create \
|
|
163
181
|
--title "feat(scope): concise description" \
|
|
164
182
|
--label "enhancement" \
|
|
165
183
|
--body "$(cat <<'ISSUE'
|
|
166
|
-
|
|
184
|
+
Concrete statement of what's currently missing or broken. Name the specific tool, service, resource, or domain area. Two or three sentences — the reader should know the gap before the end of the paragraph.
|
|
167
185
|
|
|
168
|
-
|
|
186
|
+
Related: #N
|
|
187
|
+
|
|
188
|
+
## Proposal
|
|
189
|
+
|
|
190
|
+
What you want the server to do, in one paragraph. Link external libraries or services on first mention: [lib name](https://github.com/owner/repo). Include a short justification — what this gives users that they don't have today.
|
|
169
191
|
|
|
170
192
|
### Proposed behavior
|
|
171
193
|
|
|
172
|
-
Describe the
|
|
194
|
+
Describe the new behavior or surface. For tool/resource changes, show example input/output or the new schema fields:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
// Example: new input field or output shape
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Flow (optional)
|
|
201
|
+
|
|
202
|
+
Ordered steps — e.g. `request → lookup → fallback → respond`. Useful when the change spans multiple phases or fallbacks.
|
|
203
|
+
|
|
204
|
+
### Design / Tradeoffs (optional)
|
|
205
|
+
|
|
206
|
+
Philosophy: **one-line principle in bold.**
|
|
207
|
+
|
|
208
|
+
| Option | Strengths | Weaknesses |
|
|
209
|
+
|:---|:---|:---|
|
|
210
|
+
| A | ... | ... |
|
|
211
|
+
| B | ... | ... |
|
|
212
|
+
|
|
213
|
+
### Scope
|
|
214
|
+
|
|
215
|
+
- Files or modules touched
|
|
216
|
+
- New env vars, config keys, or service integrations
|
|
217
|
+
- New or modified tools / resources / prompts
|
|
218
|
+
|
|
219
|
+
### Out of scope
|
|
220
|
+
|
|
221
|
+
- What we're deliberately not doing
|
|
222
|
+
- Adjacent work that belongs in a separate issue
|
|
223
|
+
|
|
224
|
+
### Dependencies (optional)
|
|
225
|
+
|
|
226
|
+
- Depends on: cyanheads/mcp-ts-core#N (upstream framework change)
|
|
227
|
+
- Depends on: owner/repo#N (other server work)
|
|
173
228
|
|
|
174
229
|
### Alternatives considered
|
|
175
230
|
|
|
176
|
-
What you tried or
|
|
231
|
+
What you tried or evaluated instead, and why it didn't fit.
|
|
177
232
|
ISSUE
|
|
178
233
|
)"
|
|
179
234
|
````
|