@zuwiki/mcp 0.1.0

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.
Files changed (57) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +189 -0
  3. package/dist/api/categories.d.ts +4 -0
  4. package/dist/api/categories.js +14 -0
  5. package/dist/api/categories.js.map +1 -0
  6. package/dist/api/http.d.ts +8 -0
  7. package/dist/api/http.js +119 -0
  8. package/dist/api/http.js.map +1 -0
  9. package/dist/api/organizations.d.ts +14 -0
  10. package/dist/api/organizations.js +15 -0
  11. package/dist/api/organizations.js.map +1 -0
  12. package/dist/api/pages.d.ts +16 -0
  13. package/dist/api/pages.js +35 -0
  14. package/dist/api/pages.js.map +1 -0
  15. package/dist/api/types.d.ts +69 -0
  16. package/dist/api/types.js +13 -0
  17. package/dist/api/types.js.map +1 -0
  18. package/dist/api/wikis.d.ts +12 -0
  19. package/dist/api/wikis.js +25 -0
  20. package/dist/api/wikis.js.map +1 -0
  21. package/dist/auth/client.d.ts +54 -0
  22. package/dist/auth/client.js +162 -0
  23. package/dist/auth/client.js.map +1 -0
  24. package/dist/auth/discovery.d.ts +14 -0
  25. package/dist/auth/discovery.js +26 -0
  26. package/dist/auth/discovery.js.map +1 -0
  27. package/dist/auth/flow.d.ts +21 -0
  28. package/dist/auth/flow.js +188 -0
  29. package/dist/auth/flow.js.map +1 -0
  30. package/dist/auth/pkce.d.ts +7 -0
  31. package/dist/auth/pkce.js +20 -0
  32. package/dist/auth/pkce.js.map +1 -0
  33. package/dist/auth/registration.d.ts +21 -0
  34. package/dist/auth/registration.js +28 -0
  35. package/dist/auth/registration.js.map +1 -0
  36. package/dist/auth/tokens.d.ts +25 -0
  37. package/dist/auth/tokens.js +51 -0
  38. package/dist/auth/tokens.js.map +1 -0
  39. package/dist/cli.d.ts +2 -0
  40. package/dist/cli.js +128 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/server.d.ts +15 -0
  43. package/dist/server.js +53 -0
  44. package/dist/server.js.map +1 -0
  45. package/dist/tools/register.d.ts +12 -0
  46. package/dist/tools/register.js +244 -0
  47. package/dist/tools/register.js.map +1 -0
  48. package/dist/tools/shared.d.ts +5 -0
  49. package/dist/tools/shared.js +38 -0
  50. package/dist/tools/shared.js.map +1 -0
  51. package/dist/transports/http.d.ts +9 -0
  52. package/dist/transports/http.js +150 -0
  53. package/dist/transports/http.js.map +1 -0
  54. package/dist/transports/stdio.d.ts +7 -0
  55. package/dist/transports/stdio.js +20 -0
  56. package/dist/transports/stdio.js.map +1 -0
  57. package/package.json +41 -0
@@ -0,0 +1,150 @@
1
+ import { createServer } from "node:http";
2
+ import { randomUUID } from "node:crypto";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
5
+ import { buildServer } from "../server.js";
6
+ export async function startHttp(opts) {
7
+ const sessions = new Map();
8
+ const mcpPath = opts.path ?? "/mcp";
9
+ const server = createServer(async (req, res) => {
10
+ try {
11
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
12
+ if (url.pathname !== mcpPath) {
13
+ res.statusCode = 404;
14
+ res.setHeader("content-type", "application/json");
15
+ res.end(JSON.stringify({ error: "not_found" }));
16
+ return;
17
+ }
18
+ const auth = parseAuthInfo(req);
19
+ if (!auth) {
20
+ sendUnauthorized(res, opts.baseUrl);
21
+ return;
22
+ }
23
+ req.auth = auth;
24
+ const body = await readJsonBody(req);
25
+ const sessionId = req.headers["mcp-session-id"];
26
+ let entry = sessionId ? sessions.get(sessionId) : undefined;
27
+ if (!entry) {
28
+ if (sessionId) {
29
+ res.statusCode = 404;
30
+ res.setHeader("content-type", "application/json");
31
+ res.end(JSON.stringify({ error: "unknown_session" }));
32
+ return;
33
+ }
34
+ if (!isInitializeRequest(body)) {
35
+ res.statusCode = 400;
36
+ res.setHeader("content-type", "application/json");
37
+ res.end(JSON.stringify({
38
+ jsonrpc: "2.0",
39
+ error: {
40
+ code: -32600,
41
+ message: "Expected an initialize request, no valid session header was provided.",
42
+ },
43
+ id: null,
44
+ }));
45
+ return;
46
+ }
47
+ entry = await createSession({
48
+ baseUrl: opts.baseUrl,
49
+ organizationId: opts.organizationId,
50
+ organizationsPath: opts.organizationsPath,
51
+ onSessionInitialized: (sid, e) => sessions.set(sid, e),
52
+ onSessionClosed: (sid) => sessions.delete(sid),
53
+ });
54
+ }
55
+ await entry.transport.handleRequest(req, res, body);
56
+ }
57
+ catch (err) {
58
+ if (!res.headersSent) {
59
+ res.statusCode = 500;
60
+ res.setHeader("content-type", "application/json");
61
+ res.end(JSON.stringify({
62
+ jsonrpc: "2.0",
63
+ error: { code: -32603, message: err.message },
64
+ id: null,
65
+ }));
66
+ }
67
+ }
68
+ });
69
+ await new Promise((resolve, reject) => {
70
+ server.once("error", reject);
71
+ server.listen(opts.port, opts.host, () => {
72
+ server.off("error", reject);
73
+ resolve();
74
+ });
75
+ });
76
+ process.stderr.write(`Zuwiki MCP HTTP server listening on http://${opts.host}:${opts.port}${mcpPath}\n`);
77
+ }
78
+ async function createSession(opts) {
79
+ let entry;
80
+ const transport = new StreamableHTTPServerTransport({
81
+ sessionIdGenerator: () => randomUUID(),
82
+ onsessioninitialized: (sessionId) => {
83
+ opts.onSessionInitialized(sessionId, entry);
84
+ },
85
+ });
86
+ transport.onclose = () => {
87
+ const id = transport.sessionId;
88
+ if (id)
89
+ opts.onSessionClosed(id);
90
+ };
91
+ const built = buildServer({
92
+ baseUrl: opts.baseUrl,
93
+ organizationId: opts.organizationId,
94
+ organizationsPath: opts.organizationsPath,
95
+ });
96
+ await built.server.connect(transport);
97
+ entry = {
98
+ transport,
99
+ close: async () => {
100
+ await transport.close().catch(() => undefined);
101
+ },
102
+ };
103
+ return entry;
104
+ }
105
+ function parseAuthInfo(req) {
106
+ const header = req.headers.authorization;
107
+ if (!header || Array.isArray(header))
108
+ return null;
109
+ const match = /^bearer\s+(.+)$/i.exec(header);
110
+ if (!match)
111
+ return null;
112
+ const token = (match[1] ?? "").trim();
113
+ if (!token)
114
+ return null;
115
+ return {
116
+ token,
117
+ clientId: "",
118
+ scopes: [],
119
+ };
120
+ }
121
+ function sendUnauthorized(res, baseUrl) {
122
+ const trimmed = baseUrl.replace(/\/+$/, "");
123
+ res.statusCode = 401;
124
+ res.setHeader("www-authenticate", `Bearer resource_metadata="${trimmed}/.well-known/oauth-protected-resource"`);
125
+ res.setHeader("content-type", "application/json");
126
+ res.end(JSON.stringify({
127
+ error: "unauthorized",
128
+ error_description: "Authorization Header mit Bearer Token erforderlich. Beziehe einen Token vom Zuwiki Auth Server.",
129
+ }));
130
+ }
131
+ async function readJsonBody(req) {
132
+ if (req.method !== "POST")
133
+ return undefined;
134
+ const chunks = [];
135
+ for await (const chunk of req) {
136
+ chunks.push(chunk);
137
+ }
138
+ if (chunks.length === 0)
139
+ return undefined;
140
+ const text = Buffer.concat(chunks).toString("utf8");
141
+ if (!text)
142
+ return undefined;
143
+ try {
144
+ return JSON.parse(text);
145
+ }
146
+ catch {
147
+ return undefined;
148
+ }
149
+ }
150
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface StdioTransportOptions {
2
+ baseUrl: string;
3
+ organizationId: string | null;
4
+ credentialsPath?: string;
5
+ organizationsPath?: string;
6
+ }
7
+ export declare function startStdio(opts: StdioTransportOptions): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { AuthManager } from "../auth/client.js";
3
+ import { buildServer } from "../server.js";
4
+ export async function startStdio(opts) {
5
+ const authManager = new AuthManager({
6
+ baseUrl: opts.baseUrl,
7
+ credentialsPath: opts.credentialsPath,
8
+ });
9
+ // Fetch the initial token up front so the browser flow does not happen during the first tool call.
10
+ await authManager.ensureAccessToken();
11
+ const { server } = buildServer({
12
+ baseUrl: opts.baseUrl,
13
+ authManager,
14
+ organizationId: opts.organizationId,
15
+ organizationsPath: opts.organizationsPath,
16
+ });
17
+ const transport = new StdioServerTransport();
18
+ await server.connect(transport);
19
+ }
20
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAS3C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAA2B;IAC1D,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC;QAClC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,eAAe,EAAE,IAAI,CAAC,eAAe;KACtC,CAAC,CAAC;IAEH,mGAAmG;IACnG,MAAM,WAAW,CAAC,iBAAiB,EAAE,CAAC;IAEtC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;QAC7B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,WAAW;QACX,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;KAC1C,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@zuwiki/mcp",
3
+ "version": "0.1.0",
4
+ "description": "Model Context Protocol server for Zuwiki",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "zuwiki-mcp": "dist/cli.js"
9
+ },
10
+ "main": "dist/cli.js",
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "engines": {
19
+ "node": ">=20"
20
+ },
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^1.0.4",
23
+ "open": "^10.1.0",
24
+ "zod": "^3.23.8"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^22.10.0",
28
+ "tsx": "^4.19.0",
29
+ "typescript": "^5.6.3",
30
+ "undici": "^7.0.0",
31
+ "vitest": "^2.1.0"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "dev": "tsx src/cli.ts",
36
+ "start": "node dist/cli.js",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "typecheck": "tsc --noEmit"
40
+ }
41
+ }