@xyd-js/mcp-server 0.0.0-build-9f87f13-20250930210637

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/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@xyd-js/mcp-server",
3
+ "version": "0.0.0-build-9f87f13-20250930210637",
4
+ "type": "module",
5
+ "description": "MCP server for xyd",
6
+ "main": "dist/index.js",
7
+ "exports": {
8
+ "./package.json": "./package.json",
9
+ ".": {
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "bin": {
14
+ "xyd-mcp-server": "./bin/xyd-mcp-server.mjs"
15
+ },
16
+ "dependencies": {
17
+ "@modelcontextprotocol/sdk": "^1.18.1",
18
+ "express": "^5.1.0",
19
+ "@xyd-js/mcp": "0.0.0-build-9f87f13-20250930210637"
20
+ },
21
+ "devDependencies": {
22
+ "@types/express": "^4.17.21",
23
+ "@types/node": "^20.9.0",
24
+ "openapi-typescript": "^7.4.2",
25
+ "typescript": "^5.6.2",
26
+ "@types/bun": "latest"
27
+ },
28
+ "scripts": {
29
+ "build": "bun build src/index.ts --outdir dist --target node --format esm",
30
+ "dev": "bun --watch src/index.ts",
31
+ "start": "bun dist/index.js",
32
+ "demo:simple": "bun --watch demo/simple/server.ts",
33
+ "mcp:inspector": "npx @modelcontextprotocol/inspector http://localhost:3000/mcp"
34
+ }
35
+ }
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ import express from "express";
2
+
3
+ import { MCPServer } from "./mcp";
4
+
5
+ const mcp = new MCPServer();
6
+ const app = express();
7
+
8
+ app.use(express.json());
9
+
10
+ app.post("/mcp", mcp.handleConnectionRequest);
11
+ app.get("/mcp", mcp.handleSessionRequest);
12
+ app.delete("/mcp", mcp.handleSessionRequest);
13
+
14
+ const port = process.env.PORT || 3000;
15
+ console.log("Running MCP server on port", port);
16
+
17
+ app.listen(port);
18
+
package/src/mcp.ts ADDED
@@ -0,0 +1,220 @@
1
+ import { randomUUID } from "node:crypto";
2
+
3
+ import express from "express";
4
+
5
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
6
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+
9
+ import { mcpUniformResources, mcpUniformTools } from "@xyd-js/mcp";
10
+
11
+ // Extend Express Request type to include pendingToken
12
+ declare global {
13
+ namespace Express {
14
+ interface Request {
15
+ pendingToken?: string;
16
+ }
17
+ }
18
+ }
19
+
20
+ export class MCPServer {
21
+ private transports: { [sessionId: string]: StreamableHTTPServerTransport } =
22
+ {};
23
+
24
+ // Store tokens by session ID
25
+ private sessionTokens: { [sessionId: string]: string } = {};
26
+
27
+ private uniformSource: string = "";
28
+
29
+ constructor() {
30
+ this.connect = this.connect.bind(this);
31
+ this.handleConnectionRequest = this.handleConnectionRequest.bind(this);
32
+ this.handleSessionRequest = this.handleSessionRequest.bind(this);
33
+
34
+ if (process.argv[2]) {
35
+ this.uniformSource = process.argv[2];
36
+ }
37
+ }
38
+
39
+ public async handleConnectionRequest(
40
+ req: express.Request,
41
+ res: express.Response
42
+ ): Promise<void> {
43
+ // Check for existing session ID
44
+ const sessionId = req.headers["mcp-session-id"] as string | undefined;
45
+ let transport: StreamableHTTPServerTransport;
46
+
47
+ if (sessionId && this.transports[sessionId]) {
48
+ // Reuse existing transport
49
+ transport = this.transports[sessionId];
50
+ } else if (!sessionId && isInitializeRequest(req.body)) {
51
+ // Extract and store token
52
+ const authorized = req.headers["authorization"];
53
+ const bearer = authorized?.split("Bearer");
54
+ let token = "";
55
+ if (bearer && bearer.length > 1) {
56
+ token = bearer[1].trim();
57
+ }
58
+
59
+ transport = await this.connect(token);
60
+ } else {
61
+ // Invalid request
62
+ res.status(400).json({
63
+ jsonrpc: "2.0",
64
+ error: {
65
+ code: -32000,
66
+ message: "Bad Request: No valid session ID provided",
67
+ },
68
+ id: null,
69
+ });
70
+ return;
71
+ }
72
+
73
+ // Handle the request
74
+ await transport.handleRequest(req, res, req.body);
75
+ }
76
+
77
+ public async handleSessionRequest(
78
+ req: express.Request,
79
+ res: express.Response
80
+ ): Promise<void> {
81
+ const sessionId = req.headers["mcp-session-id"] as string | undefined;
82
+ if (!sessionId || !this.transports[sessionId]) {
83
+ res.status(400).send("Invalid or missing session ID");
84
+ return;
85
+ }
86
+
87
+ const transport = this.transports[sessionId];
88
+ await transport.handleRequest(req, res);
89
+ }
90
+
91
+ private async connect(
92
+ token?: string
93
+ ): Promise<StreamableHTTPServerTransport> {
94
+ // New initialization request
95
+ const transport = new StreamableHTTPServerTransport({
96
+ sessionIdGenerator: () => randomUUID(),
97
+ onsessioninitialized: (sessionId) => {
98
+ // Store the transport by session ID
99
+ this.transports[sessionId] = transport;
100
+
101
+ // Store the token for this session if we have one
102
+ if (token) {
103
+ this.sessionTokens[sessionId] = token;
104
+ }
105
+ },
106
+ // DNS rebinding protection is disabled by default for backwards compatibility. If you are running this server
107
+ // locally, make sure to set:
108
+ // enableDnsRebindingProtection: true,
109
+ // allowedHosts: ['127.0.0.1'],
110
+ });
111
+
112
+ // Clean up transport when closed
113
+ transport.onclose = () => {
114
+ if (transport.sessionId) {
115
+ delete this.transports[transport.sessionId];
116
+ delete this.sessionTokens[transport.sessionId];
117
+ console.log("Cleaned up session:", transport.sessionId);
118
+ }
119
+ };
120
+
121
+ const server = new McpServer({
122
+ name: "xyd-mcp-server",
123
+ version: "1.0.0",
124
+ });
125
+
126
+ if (this.uniformSource) {
127
+ await mcpUniformResources(server, this.uniformSource);
128
+ }
129
+
130
+ if (token) {
131
+ await mcpUniformTools(server, this.uniformSource, token);
132
+ }
133
+
134
+ // Add simple token tool
135
+ this.addSimpleTokenTool(server);
136
+
137
+ // Connect to the MCP server
138
+ await server.connect(transport);
139
+
140
+ return transport;
141
+ }
142
+
143
+ // Simple method to add a token info tool
144
+ private addSimpleTokenTool(server: McpServer): void {
145
+ server.registerTool(
146
+ "get_token_info",
147
+ {
148
+ title: "Get Token Info",
149
+ description:
150
+ "Display information about the stored authentication token",
151
+ inputSchema: {},
152
+ },
153
+ async () => {
154
+ // Get all session info
155
+ const sessionCount = Object.keys(this.sessionTokens).length;
156
+ const sessions = Object.keys(this.sessionTokens);
157
+
158
+ if (sessionCount === 0) {
159
+ return {
160
+ content: [
161
+ {
162
+ type: "text",
163
+ text: "No authentication tokens found in any session",
164
+ },
165
+ ],
166
+ };
167
+ }
168
+
169
+ let result = `Found ${sessionCount} session(s) with tokens:\n\n`;
170
+
171
+ for (const sessionId of sessions) {
172
+ const token = this.sessionTokens[sessionId];
173
+ const maskedToken =
174
+ token.length > 10
175
+ ? `${token.substring(0, 6)}...${token.substring(token.length - 4)}`
176
+ : "***";
177
+
178
+ result += `Session: ${sessionId}\n`;
179
+ result += `Token (masked): ${maskedToken}\n`;
180
+ result += `Token length: ${token.length} characters\n\n`;
181
+ }
182
+
183
+ return {
184
+ content: [
185
+ {
186
+ type: "text",
187
+ text: result,
188
+ },
189
+ ],
190
+ };
191
+ }
192
+ );
193
+ }
194
+
195
+ // Method to get token for a specific session
196
+ public getSessionToken(sessionId: string): string | undefined {
197
+ return this.sessionTokens[sessionId];
198
+ }
199
+
200
+ // Method to get active session count
201
+ private getActiveSessionCount(): number {
202
+ return Object.keys(this.transports).length;
203
+ }
204
+
205
+ // Method to clean up a specific session
206
+ private cleanupSession(sessionId: string): boolean {
207
+ if (this.transports[sessionId]) {
208
+ delete this.transports[sessionId];
209
+ delete this.sessionTokens[sessionId];
210
+ return true;
211
+ }
212
+ return false;
213
+ }
214
+
215
+ // Method to clean up all sessions
216
+ private cleanupAllSessions(): void {
217
+ this.transports = {};
218
+ this.sessionTokens = {};
219
+ }
220
+ }