Skip to content

Commit e7d4391

Browse files
Merge branch 'main' into feature/example-decorators
2 parents c80f0ab + 7d7e62c commit e7d4391

6 files changed

Lines changed: 90 additions & 47 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/core': patch
3+
---
4+
5+
Fix `requestStream` to call `tasks/result` for failed tasks instead of yielding a hardcoded `ProtocolError`. When a task reaches the `failed` terminal status, the stream now retrieves and yields the actual stored result (matching the behavior for `completed` tasks), as required by the spec.

README.md

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
- [Overview](#overview)
1515
- [Packages](#packages)
1616
- [Installation](#installation)
17-
- [Quick Start (runnable examples)](#quick-start-runnable-examples)
17+
- [Getting Started](#getting-started)
1818
- [Documentation](#documentation)
1919
- [Contributing](#contributing)
2020
- [License](#license)
@@ -90,59 +90,53 @@ npm install @modelcontextprotocol/express express
9090
npm install @modelcontextprotocol/hono hono
9191
```
9292

93-
## Quick Start (runnable examples)
93+
## Getting Started
9494

95-
The runnable examples live under `examples/` and are kept in sync with the docs.
95+
Here is what an MCP server looks like. This minimal example exposes a single `greet` tool over stdio:
9696

97-
1. **Install dependencies** (from repo root):
97+
```typescript
98+
import { McpServer, StdioServerTransport } from '@modelcontextprotocol/server';
99+
import * as z from 'zod/v4';
98100

99-
```bash
100-
pnpm install
101-
```
102-
103-
2. **Run a Streamable HTTP example server**:
104-
105-
```bash
106-
pnpm --filter @modelcontextprotocol/examples-server exec tsx src/simpleStreamableHttp.ts
107-
```
101+
const server = new McpServer({ name: 'greeting-server', version: '1.0.0' });
108102

109-
Alternatively, from within the example package:
103+
server.registerTool(
104+
'greet',
105+
{
106+
description: 'Greet someone by name',
107+
inputSchema: z.object({ name: z.string() }),
108+
},
109+
async ({ name }) => ({
110+
content: [{ type: 'text', text: `Hello, ${name}!` }],
111+
}),
112+
);
110113

111-
```bash
112-
cd examples/server
113-
pnpm tsx src/simpleStreamableHttp.ts
114-
```
115-
116-
3. **Run the interactive client in another terminal**:
114+
async function main() {
115+
const transport = new StdioServerTransport();
116+
await server.connect(transport);
117+
}
117118

118-
```bash
119-
pnpm --filter @modelcontextprotocol/examples-client exec tsx src/simpleStreamableHttp.ts
119+
main();
120120
```
121121

122-
Alternatively, from within the example package:
122+
Ready to build something real? Follow the step-by-step quickstart tutorials:
123123

124-
```bash
125-
cd examples/client
126-
pnpm tsx src/simpleStreamableHttp.ts
127-
```
124+
- [Build a weather server](docs/server-quickstart.md) — server quickstart
125+
- [Build an LLM-powered chatbot](docs/client-quickstart.md) — client quickstart
128126

129-
Next steps:
127+
The complete code for each tutorial is in [`examples/server-quickstart/`](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/examples/server-quickstart/) and [`examples/client-quickstart/`](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/examples/client-quickstart/). For more advanced runnable examples, see:
130128

131-
- Server examples index: [`examples/server/README.md`](examples/server/README.md)
132-
- Client examples index: [`examples/client/README.md`](examples/client/README.md)
133-
- Guided walkthroughs: [`docs/server.md`](docs/server.md) and [`docs/client.md`](docs/client.md)
129+
- [`examples/server/README.md`](examples/server/README.md) — server examples index
130+
- [`examples/client/README.md`](examples/client/README.md) — client examples index
134131

135132
## Documentation
136133

137-
- Local SDK docs:
138-
- [docs/server.md](docs/server.md) – building MCP servers: transports, tools, resources, prompts, server-initiated requests, and deployment
139-
- [docs/client.md](docs/client.md) – building MCP clients: connecting, tools, resources, prompts, server-initiated requests, and error handling
140-
- [docs/faq.md](docs/faq.md) – frequently asked questions and troubleshooting
141-
- External references:
142-
- [SDK API documentation](https://ts.sdk.modelcontextprotocol.io/)
143-
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
144-
- [MCP Specification](https://spec.modelcontextprotocol.io)
145-
- [Example Servers](https://github.com/modelcontextprotocol/servers)
134+
- [Server Guide](docs/server.md) — building MCP servers: transports, tools, resources, prompts, server-initiated requests, and deployment
135+
- [Client Guide](docs/client.md) — building MCP clients: connecting, tools, resources, prompts, server-initiated requests, and error handling
136+
- [FAQ](docs/faq.md) — frequently asked questions and troubleshooting
137+
- [API docs](https://modelcontextprotocol.github.io/typescript-sdk/)
138+
- [MCP documentation](https://modelcontextprotocol.io/docs)
139+
- [MCP specification](https://modelcontextprotocol.io/specification/latest)
146140

147141
### Building docs locally
148142

docs/faq.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ For production use, you can either:
6767

6868
### Where can I find runnable server examples?
6969

70-
The SDK ships several runnable server examples under `examples/server/src`. Start from the server examples index in [`examples/server/README.md`](../examples/server/README.md) and the entry-point quick start in the root [`README.md`](../README.md).
70+
The [server quickstart](./server-quickstart.md) walks you through building a weather server from scratch. Its complete source lives in [`examples/server-quickstart/`](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/examples/server-quickstart/). For more advanced examples (OAuth, streaming, sessions, etc.), see the server examples index in [`examples/server/README.md`](../examples/server/README.md).
7171

7272
### Why did we remove `server` auth exports?
7373

packages/core/src/shared/taskManager.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,15 +302,12 @@ export class TaskManager {
302302

303303
if (isTerminal(task.status)) {
304304
switch (task.status) {
305-
case 'completed': {
305+
case 'completed':
306+
case 'failed': {
306307
const result = await this.getTaskResult({ taskId }, resultSchema, options);
307308
yield { type: 'result', result };
308309
break;
309310
}
310-
case 'failed': {
311-
yield { type: 'error', error: new ProtocolError(ProtocolErrorCode.InternalError, `Task ${taskId} failed`) };
312-
break;
313-
}
314311
case 'cancelled': {
315312
yield {
316313
type: 'error',

packages/core/src/types/spec.types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Source: https://github.com/modelcontextprotocol/modelcontextprotocol
55
* Pulled from: https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/main/schema/draft/schema.ts
6-
* Last updated from commit: 838d6f69055f1d14400d67a47eb1d76207c7c34b
6+
* Last updated from commit: 5c25208be86db5033f644a4e0d005e08f699ef3d
77
*
88
* DO NOT EDIT THIS FILE MANUALLY. Changes will be overwritten by automated updates.
99
* To update this file, run: pnpm run fetch:spec-types
@@ -1848,6 +1848,7 @@ export interface Task {
18481848

18491849
/**
18501850
* Actual retention duration from creation in milliseconds, null for unlimited.
1851+
* @nullable
18511852
*/
18521853
ttl: number | null;
18531854

@@ -2628,6 +2629,8 @@ export interface CompleteResult extends Result {
26282629
completion: {
26292630
/**
26302631
* An array of completion values. Must not exceed 100 items.
2632+
*
2633+
* @maxItems 100
26312634
*/
26322635
values: string[];
26332636
/**

test/integration/test/taskLifecycle.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,50 @@ describe('Task Lifecycle Integration Tests', () => {
15021502
});
15031503
});
15041504

1505+
describe('callToolStream with failed task', () => {
1506+
it('should yield stored result (isError: true) when task fails, not a generic ProtocolError', async () => {
1507+
const client = new Client(
1508+
{
1509+
name: 'test-client',
1510+
version: '1.0.0'
1511+
},
1512+
{
1513+
capabilities: { tasks: {} }
1514+
}
1515+
);
1516+
1517+
const transport = new StreamableHTTPClientTransport(baseUrl);
1518+
await client.connect(transport);
1519+
1520+
// Use callToolStream with shouldFail: true so the tool stores a failed result
1521+
const stream = client.experimental.tasks.callToolStream(
1522+
{ name: 'long-task', arguments: { duration: 100, shouldFail: true } },
1523+
{ task: { ttl: 60_000 } }
1524+
);
1525+
1526+
// Collect all stream messages
1527+
const messages: Array<{ type: string; task?: unknown; result?: unknown; error?: unknown }> = [];
1528+
for await (const message of stream) {
1529+
messages.push(message);
1530+
}
1531+
1532+
// First message should be taskCreated
1533+
expect(messages[0]!.type).toBe('taskCreated');
1534+
1535+
// Last message must be 'result' (carrying the stored isError content),
1536+
// NOT 'error' (which would mean the generic hardcoded ProtocolError was returned)
1537+
const lastMessage = messages.at(-1)!;
1538+
expect(lastMessage.type).toBe('result');
1539+
1540+
// The stored result should contain isError: true and the real failure content
1541+
const result = lastMessage.result as { content: Array<{ type: string; text: string }>; isError: boolean };
1542+
expect(result.isError).toBe(true);
1543+
expect(result.content).toEqual([{ type: 'text', text: 'Task failed as requested' }]);
1544+
1545+
await transport.close();
1546+
}, 15_000);
1547+
});
1548+
15051549
describe('callToolStream with elicitation', () => {
15061550
it('should deliver elicitation via callToolStream and complete task', async () => {
15071551
const client = new Client(

0 commit comments

Comments
 (0)