Merge branch 'main' into server-authorization-proxy

This commit is contained in:
Allen Zhou 2025-03-17 15:35:51 -07:00 • committed by GitHub
commit 514f5493b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 97 additions and 2 deletions

25
CLAUDE.md Normal file
View file

@ -0,0 +1,25 @@
# MCP TypeScript SDK Guide
## Build & Test Commands
```
npm run build # Build ESM and CJS versions
npm run lint # Run ESLint
npm test # Run all tests
npx jest path/to/file.test.ts # Run specific test file
npx jest -t "test name" # Run tests matching pattern
```
## Code Style Guidelines
- **TypeScript**: Strict type checking, ES modules, explicit return types
- **Naming**: PascalCase for classes/types, camelCase for functions/variables
- **Files**: Lowercase with hyphens, test files with `.test.ts` suffix
- **Imports**: ES module style, include `.js` extension, group imports logically
- **Error Handling**: Use TypeScript's strict mode, explicit error checking in tests
- **Formatting**: 2-space indentation, semicolons required, single quotes preferred
- **Testing**: Co-locate tests with source files, use descriptive test names
- **Comments**: JSDoc for public APIs, inline comments for complex logic
## Project Structure
- `/src`: Source code with client, server, and shared modules
- Tests alongside source files with `.test.ts` suffix
- Node.js >= 18 required

View file

@ -1,6 +1,6 @@
{
"name": "@modelcontextprotocol/sdk",
"version": "1.6.0",
"version": "1.7.0",
"description": "Model Context Protocol implementation for TypeScript",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",

View file

@ -11,6 +11,7 @@ export class InMemoryTransport implements Transport {
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
sessionId?: string;
/**
* Creates a pair of linked in-memory transports that can communicate with each other. One should be passed to a Client and one to a Server.

View file

@ -323,6 +323,59 @@ describe("tool()", () => {
mcpServer.tool("tool2", () => ({ content: [] }));
});
test("should pass sessionId to tool callback via RequestHandlerExtra", async () => {
const mcpServer = new McpServer({
name: "test server",
version: "1.0",
});
const client = new Client(
{
name: "test client",
version: "1.0",
},
{
capabilities: {
tools: {},
},
},
);
let receivedSessionId: string | undefined;
mcpServer.tool("test-tool", async (extra) => {
receivedSessionId = extra.sessionId;
return {
content: [
{
type: "text",
text: "Test response",
},
],
};
});
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
// Set a test sessionId on the server transport
serverTransport.sessionId = "test-session-123";
await Promise.all([
client.connect(clientTransport),
mcpServer.server.connect(serverTransport),
]);
await client.request(
{
method: "tools/call",
params: {
name: "test-tool",
},
},
CallToolResultSchema,
);
expect(receivedSessionId).toBe("test-session-123");
});
test("should allow client to call server tools", async () => {
const mcpServer = new McpServer({
name: "test server",

View file

@ -88,6 +88,11 @@ export type RequestHandlerExtra = {
* An abort signal used to communicate if the request was cancelled from the sender's side.
*/
signal: AbortSignal;
/**
* The session ID from the transport, if available.
*/
sessionId?: string;
};
/**
@ -307,9 +312,15 @@ export abstract class Protocol<
const abortController = new AbortController();
this._requestHandlerAbortControllers.set(request.id, abortController);
// Create extra object with both abort signal and sessionId from transport
const extra: RequestHandlerExtra = {
signal: abortController.signal,
sessionId: this._transport?.sessionId,
};
// Starting with Promise.resolve() puts any synchronous errors into the monad as well.
Promise.resolve()
.then(() => handler(request, { signal: abortController.signal }))
.then(() => handler(request, extra))
.then(
(result) => {
if (abortController.signal.aborted) {

View file

@ -41,4 +41,9 @@ export interface Transport {
* Callback for when a message (request or response) is received over the connection.
*/
onmessage?: (message: JSONRPCMessage) => void;
/**
* The session ID generated for this connection.
*/
sessionId?: string;
}