gtfs-pro-mcp 1.0.0 → 1.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.
- package/README.md +73 -4
- package/dist/http.d.ts +17 -0
- package/dist/http.js +121 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +8 -18
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +15 -0
- package/dist/server.js +27 -0
- package/dist/server.js.map +1 -0
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -88,6 +88,29 @@ Edit `claude_desktop_config.json` (Settings → Developer → Edit Config) and a
|
|
|
88
88
|
Restart Claude Desktop, then ask: *"What bus stops are near \<a place in the
|
|
89
89
|
service area\>?"* or *"When's the next bus from \<stop name\>?"*
|
|
90
90
|
|
|
91
|
+
> **Windows users:** Claude Desktop on Windows can't launch `npx` directly (it's a
|
|
92
|
+
> `.cmd` shim, not an executable), so the server silently fails to start and Claude
|
|
93
|
+
> falls back to web search. Wrap the command in `cmd` instead:
|
|
94
|
+
>
|
|
95
|
+
> ```json
|
|
96
|
+
> {
|
|
97
|
+
> "mcpServers": {
|
|
98
|
+
> "gtfs-pro-transit": {
|
|
99
|
+
> "command": "cmd",
|
|
100
|
+
> "args": ["/c", "npx", "-y", "gtfs-pro-mcp"],
|
|
101
|
+
> "env": {
|
|
102
|
+
> "GTFS_PRO_URL": "https://your-agency-site.org",
|
|
103
|
+
> "GTFS_PRO_FEED_ID": "default",
|
|
104
|
+
> "GTFS_PRO_AGENCY_NAME": "Your Transit Agency"
|
|
105
|
+
> }
|
|
106
|
+
> }
|
|
107
|
+
> }
|
|
108
|
+
> }
|
|
109
|
+
> ```
|
|
110
|
+
>
|
|
111
|
+
> After editing, fully **quit** Claude Desktop (right-click the system-tray icon →
|
|
112
|
+
> Quit — closing the window isn't enough) and reopen it.
|
|
113
|
+
|
|
91
114
|
## Use with ChatGPT / other MCP clients
|
|
92
115
|
|
|
93
116
|
Any client that launches a local stdio MCP server works the same way — run
|
|
@@ -98,6 +121,46 @@ npm install -g gtfs-pro-mcp
|
|
|
98
121
|
GTFS_PRO_URL=https://your-agency-site.org gtfs-pro-mcp
|
|
99
122
|
```
|
|
100
123
|
|
|
124
|
+
## Remote / hosted connector (Streamable HTTP)
|
|
125
|
+
|
|
126
|
+
The stdio setup above only works in clients that launch a **local process** (classic
|
|
127
|
+
Claude Desktop, Cursor, etc.). The **Claude apps that use remote connectors** — the
|
|
128
|
+
newer desktop app and **claude.ai on the web** — instead add an MCP server by **URL**.
|
|
129
|
+
For those, run the server in **HTTP mode** and host it somewhere with a public HTTPS
|
|
130
|
+
address; then add that URL as a custom connector.
|
|
131
|
+
|
|
132
|
+
Run it in HTTP mode:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
GTFS_PRO_URL=https://your-agency-site.org \
|
|
136
|
+
GTFS_PRO_AGENCY_NAME="Your Transit Agency" \
|
|
137
|
+
PORT=3000 \
|
|
138
|
+
gtfs-pro-mcp-http # or: npm run start:http
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This serves the MCP endpoint at **`/mcp`** (and a `/healthz` check). Extra env:
|
|
142
|
+
|
|
143
|
+
| Env | Default | Notes |
|
|
144
|
+
|-----|---------|-------|
|
|
145
|
+
| `PORT` | `3000` | Most hosts inject this automatically |
|
|
146
|
+
| `MCP_AUTH_TOKEN` | — | Optional. If set, clients must send `Authorization: Bearer <token>`. Leave unset for an open server — the transit data is public. |
|
|
147
|
+
|
|
148
|
+
### Deploy
|
|
149
|
+
|
|
150
|
+
- **Docker:** a `Dockerfile` is included — `docker build -t gtfs-pro-mcp . && docker run -p 3000:3000 -e GTFS_PRO_URL=… -e GTFS_PRO_AGENCY_NAME=… gtfs-pro-mcp`
|
|
151
|
+
- **Render / Railway / Fly.io (Node):** build `npm install && npm run build`, start `npm run start:http`, set the env vars. A `render.yaml` blueprint is included; Render gives you HTTPS automatically.
|
|
152
|
+
- **Your own VPS:** run behind nginx/Caddy with TLS, proxying to the Node port.
|
|
153
|
+
|
|
154
|
+
The data is public and read-only, so an open endpoint is fine; add `MCP_AUTH_TOKEN`
|
|
155
|
+
if you'd rather gate it.
|
|
156
|
+
|
|
157
|
+
### Add it to Claude
|
|
158
|
+
|
|
159
|
+
In the Claude desktop app or claude.ai: **Settings → Connectors → Add custom
|
|
160
|
+
connector**, give it a name, and paste your server's URL ending in **`/mcp`**
|
|
161
|
+
(e.g. `https://gtfs-pro-mcp.onrender.com/mcp`). Then ask a transit question and
|
|
162
|
+
you'll see the `gtfs-pro-transit` tools used.
|
|
163
|
+
|
|
101
164
|
## Local development
|
|
102
165
|
|
|
103
166
|
```bash
|
|
@@ -109,12 +172,18 @@ node test/smoke.mjs # exercise all 9 tools against a live site
|
|
|
109
172
|
## How it fits together
|
|
110
173
|
|
|
111
174
|
```
|
|
112
|
-
|
|
113
|
-
|
|
175
|
+
Local (stdio):
|
|
176
|
+
AI client ──MCP/stdio──► gtfs-pro-mcp ──HTTPS──► WP GTFS Pro REST API
|
|
177
|
+
(Desktop) (local process) /wp-json/wp-gtfs-pro/v1/*
|
|
178
|
+
|
|
179
|
+
Remote (Streamable HTTP):
|
|
180
|
+
AI client ──MCP/HTTPS──► gtfs-pro-mcp-http ──HTTPS──► WP GTFS Pro REST API
|
|
181
|
+
(web/app) (hosted service /mcp) /wp-json/wp-gtfs-pro/v1/*
|
|
114
182
|
```
|
|
115
183
|
|
|
116
|
-
|
|
117
|
-
|
|
184
|
+
Both transports share the same nine tools and config — pick stdio for local
|
|
185
|
+
clients (Claude Desktop, Cursor) or HTTP for connector-based clients (the Claude
|
|
186
|
+
app, claude.ai web, ChatGPT).
|
|
118
187
|
|
|
119
188
|
## License
|
|
120
189
|
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GTFS Pro MCP server — Streamable HTTP entry point (remote / hosted transport).
|
|
4
|
+
*
|
|
5
|
+
* This lets the server run as a public service that AI clients add as a "custom
|
|
6
|
+
* connector" by URL — Claude (desktop + web), ChatGPT, etc. — with no local
|
|
7
|
+
* install. It implements the MCP Streamable HTTP transport with per-client
|
|
8
|
+
* sessions, exposes a single `/mcp` endpoint (POST to send, GET for the SSE
|
|
9
|
+
* stream, DELETE to end a session), plus `/healthz`.
|
|
10
|
+
*
|
|
11
|
+
* Config is the same as the stdio server (GTFS_PRO_URL, etc.). Extra env:
|
|
12
|
+
* PORT - listen port (default 3000; most hosts inject this)
|
|
13
|
+
* MCP_AUTH_TOKEN - optional. If set, clients must send `Authorization:
|
|
14
|
+
* Bearer <token>`. Leave unset for an open server (the
|
|
15
|
+
* underlying transit data is public anyway).
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GTFS Pro MCP server — Streamable HTTP entry point (remote / hosted transport).
|
|
4
|
+
*
|
|
5
|
+
* This lets the server run as a public service that AI clients add as a "custom
|
|
6
|
+
* connector" by URL — Claude (desktop + web), ChatGPT, etc. — with no local
|
|
7
|
+
* install. It implements the MCP Streamable HTTP transport with per-client
|
|
8
|
+
* sessions, exposes a single `/mcp` endpoint (POST to send, GET for the SSE
|
|
9
|
+
* stream, DELETE to end a session), plus `/healthz`.
|
|
10
|
+
*
|
|
11
|
+
* Config is the same as the stdio server (GTFS_PRO_URL, etc.). Extra env:
|
|
12
|
+
* PORT - listen port (default 3000; most hosts inject this)
|
|
13
|
+
* MCP_AUTH_TOKEN - optional. If set, clients must send `Authorization:
|
|
14
|
+
* Bearer <token>`. Leave unset for an open server (the
|
|
15
|
+
* underlying transit data is public anyway).
|
|
16
|
+
*/
|
|
17
|
+
import express from "express";
|
|
18
|
+
import { randomUUID } from "node:crypto";
|
|
19
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
20
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
21
|
+
import { loadConfig } from "./config.js";
|
|
22
|
+
import { ApiClient } from "./api-client.js";
|
|
23
|
+
import { createServer } from "./server.js";
|
|
24
|
+
const config = loadConfig();
|
|
25
|
+
const api = new ApiClient(config); // shared across sessions → shared response cache
|
|
26
|
+
const PORT = Number(process.env.PORT || 3000);
|
|
27
|
+
const AUTH = (process.env.MCP_AUTH_TOKEN || "").trim();
|
|
28
|
+
const app = express();
|
|
29
|
+
app.use(express.json({ limit: "1mb" }));
|
|
30
|
+
// CORS — required for browser-based MCP clients (e.g. claude.ai web). The
|
|
31
|
+
// session id travels in the `mcp-session-id` header, so it must be allowed and
|
|
32
|
+
// exposed. Data is public, so origin is open.
|
|
33
|
+
app.use((req, res, next) => {
|
|
34
|
+
res.setHeader("Access-Control-Allow-Origin", req.headers.origin || "*");
|
|
35
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
36
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, mcp-session-id, mcp-protocol-version, last-event-id");
|
|
37
|
+
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id");
|
|
38
|
+
res.setHeader("Vary", "Origin");
|
|
39
|
+
if (req.method === "OPTIONS") {
|
|
40
|
+
res.sendStatus(204);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
next();
|
|
44
|
+
});
|
|
45
|
+
/** Optional bearer-token gate. Returns true if the request may proceed. */
|
|
46
|
+
function authorized(req, res) {
|
|
47
|
+
if (!AUTH)
|
|
48
|
+
return true;
|
|
49
|
+
if (req.headers.authorization === `Bearer ${AUTH}`)
|
|
50
|
+
return true;
|
|
51
|
+
res.status(401).json({
|
|
52
|
+
jsonrpc: "2.0",
|
|
53
|
+
error: { code: -32001, message: "Unauthorized" },
|
|
54
|
+
id: null,
|
|
55
|
+
});
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
app.get("/healthz", (_req, res) => {
|
|
59
|
+
res.json({ ok: true, agency: config.agencyName, site: config.gtfsProUrl });
|
|
60
|
+
});
|
|
61
|
+
app.get("/", (_req, res) => {
|
|
62
|
+
res.type("text/plain").send(`gtfs-pro-mcp (Streamable HTTP) for ${config.agencyName}. ` +
|
|
63
|
+
`MCP endpoint: POST ${"/mcp"}. Add this server's URL as a custom connector in your AI client.`);
|
|
64
|
+
});
|
|
65
|
+
// Live sessions, keyed by the transport's session id.
|
|
66
|
+
const transports = new Map();
|
|
67
|
+
const sid = (req) => {
|
|
68
|
+
const h = req.headers["mcp-session-id"];
|
|
69
|
+
return Array.isArray(h) ? h[0] : h;
|
|
70
|
+
};
|
|
71
|
+
// POST /mcp — client → server messages. An initialize request with no session
|
|
72
|
+
// id spins up a fresh session+server; everything else must carry a known id.
|
|
73
|
+
app.post("/mcp", async (req, res) => {
|
|
74
|
+
if (!authorized(req, res))
|
|
75
|
+
return;
|
|
76
|
+
const id = sid(req);
|
|
77
|
+
let transport = id ? transports.get(id) : undefined;
|
|
78
|
+
if (!transport) {
|
|
79
|
+
if (id || !isInitializeRequest(req.body)) {
|
|
80
|
+
res.status(400).json({
|
|
81
|
+
jsonrpc: "2.0",
|
|
82
|
+
error: { code: -32000, message: "Bad Request: no valid session ID for a non-initialize request" },
|
|
83
|
+
id: null,
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
transport = new StreamableHTTPServerTransport({
|
|
88
|
+
sessionIdGenerator: () => randomUUID(),
|
|
89
|
+
onsessioninitialized: (newId) => {
|
|
90
|
+
transports.set(newId, transport);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
transport.onclose = () => {
|
|
94
|
+
if (transport.sessionId)
|
|
95
|
+
transports.delete(transport.sessionId);
|
|
96
|
+
};
|
|
97
|
+
const server = createServer(config, api);
|
|
98
|
+
await server.connect(transport);
|
|
99
|
+
}
|
|
100
|
+
await transport.handleRequest(req, res, req.body);
|
|
101
|
+
});
|
|
102
|
+
// GET /mcp (open the SSE stream) and DELETE /mcp (end the session) both operate
|
|
103
|
+
// on an existing session.
|
|
104
|
+
async function existingSession(req, res) {
|
|
105
|
+
if (!authorized(req, res))
|
|
106
|
+
return;
|
|
107
|
+
const id = sid(req);
|
|
108
|
+
const transport = id ? transports.get(id) : undefined;
|
|
109
|
+
if (!transport) {
|
|
110
|
+
res.status(400).send("Invalid or missing session ID");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
await transport.handleRequest(req, res);
|
|
114
|
+
}
|
|
115
|
+
app.get("/mcp", existingSession);
|
|
116
|
+
app.delete("/mcp", existingSession);
|
|
117
|
+
app.listen(PORT, () => {
|
|
118
|
+
console.error(`gtfs-pro-mcp ready (http) — listening on :${PORT}, agency: ${config.agencyName}, ` +
|
|
119
|
+
`site: ${config.gtfsProUrl}${AUTH ? " [auth required]" : ""}`);
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,OAAwC,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,iDAAiD;AACpF,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC9C,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAEvD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAExC,0EAA0E;AAC1E,+EAA+E;AAC/E,8CAA8C;AAC9C,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;IACzB,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;IACxE,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,4BAA4B,CAAC,CAAC;IAC5E,GAAG,CAAC,SAAS,CACX,8BAA8B,EAC9B,kFAAkF,CACnF,CAAC;IACF,GAAG,CAAC,SAAS,CAAC,+BAA+B,EAAE,gBAAgB,CAAC,CAAC;IACjE,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACpB,OAAO;IACT,CAAC;IACD,IAAI,EAAE,CAAC;AACT,CAAC,CAAC,CAAC;AAEH,2EAA2E;AAC3E,SAAS,UAAU,CAAC,GAAY,EAAE,GAAa;IAC7C,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,KAAK,UAAU,IAAI,EAAE;QAAE,OAAO,IAAI,CAAC;IAChE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE;QAChD,EAAE,EAAE,IAAI;KACT,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IAChC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACzB,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CACzB,sCAAsC,MAAM,CAAC,UAAU,IAAI;QACzD,sBAAsB,MAAM,kEAAkE,CACjG,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,sDAAsD;AACtD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAyC,CAAC;AAEpE,MAAM,GAAG,GAAG,CAAC,GAAY,EAAsB,EAAE;IAC/C,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,8EAA8E;AAC9E,6EAA6E;AAC7E,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IAClC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;QAAE,OAAO;IAElC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,IAAI,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEpD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,IAAI,EAAE,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,+DAA+D,EAAE;gBACjG,EAAE,EAAE,IAAI;aACT,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,SAAS,GAAG,IAAI,6BAA6B,CAAC;YAC5C,kBAAkB,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;YACtC,oBAAoB,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC9B,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,SAAU,CAAC,CAAC;YACpC,CAAC;SACF,CAAC,CAAC;QACH,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;YACvB,IAAI,SAAU,CAAC,SAAS;gBAAE,UAAU,CAAC,MAAM,CAAC,SAAU,CAAC,SAAS,CAAC,CAAC;QACpE,CAAC,CAAC;QACF,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACzC,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,gFAAgF;AAChF,0BAA0B;AAC1B,KAAK,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa;IACxD,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;QAAE,OAAO;IAClC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IACD,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1C,CAAC;AAED,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AACjC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEpC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,KAAK,CACX,6CAA6C,IAAI,aAAa,MAAM,CAAC,UAAU,IAAI;QACjF,SAAS,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,CAChE,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* GTFS Pro MCP server — entry point.
|
|
3
|
+
* GTFS Pro MCP server — stdio entry point.
|
|
4
4
|
*
|
|
5
|
-
* Loads configuration, builds the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* the stdout JSON-RPC stream.
|
|
5
|
+
* Loads configuration, builds the server, and speaks MCP over stdio (the
|
|
6
|
+
* transport Claude Desktop / Cursor / ChatGPT desktop use to launch a local
|
|
7
|
+
* server). For the hosted/remote transport see `http.ts`. All diagnostics go to
|
|
8
|
+
* stderr so they never corrupt the stdout JSON-RPC stream.
|
|
9
9
|
*/
|
|
10
10
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,32 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* GTFS Pro MCP server — entry point.
|
|
3
|
+
* GTFS Pro MCP server — stdio entry point.
|
|
4
4
|
*
|
|
5
|
-
* Loads configuration, builds the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* the stdout JSON-RPC stream.
|
|
5
|
+
* Loads configuration, builds the server, and speaks MCP over stdio (the
|
|
6
|
+
* transport Claude Desktop / Cursor / ChatGPT desktop use to launch a local
|
|
7
|
+
* server). For the hosted/remote transport see `http.ts`. All diagnostics go to
|
|
8
|
+
* stderr so they never corrupt the stdout JSON-RPC stream.
|
|
9
9
|
*/
|
|
10
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
10
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
11
|
import { loadConfig } from "./config.js";
|
|
13
|
-
import {
|
|
14
|
-
import { registerTools } from "./tools.js";
|
|
12
|
+
import { createServer } from "./server.js";
|
|
15
13
|
async function main() {
|
|
16
14
|
const config = loadConfig();
|
|
17
|
-
const
|
|
18
|
-
const instructions = `This server provides real-time transit information for ${config.agencyName}.` +
|
|
19
|
-
(config.agencyDescription ? ` ${config.agencyDescription}` : "") +
|
|
20
|
-
` Use the tools to look up bus stops, schedules, routes, live vehicle positions, ` +
|
|
21
|
-
`and service alerts. Always use the tools for schedule and stop data — never guess ` +
|
|
22
|
-
`times. Note: realtime tools (get_service_alerts, get_live_vehicles) returning an ` +
|
|
23
|
-
`empty result is normal and means "nothing active right now," not "no service."`;
|
|
24
|
-
const server = new McpServer({ name: "gtfs-pro-transit", version: "1.0.0" }, { instructions });
|
|
25
|
-
registerTools(server, api);
|
|
15
|
+
const server = createServer(config);
|
|
26
16
|
const transport = new StdioServerTransport();
|
|
27
17
|
await server.connect(transport);
|
|
28
18
|
// Visible in the client's MCP logs; harmless on stderr.
|
|
29
|
-
console.error(`gtfs-pro-mcp ready — agency: ${config.agencyName}, site: ${config.gtfsProUrl}, ` +
|
|
19
|
+
console.error(`gtfs-pro-mcp ready (stdio) — agency: ${config.agencyName}, site: ${config.gtfsProUrl}, ` +
|
|
30
20
|
`default feed: ${config.feedId}`);
|
|
31
21
|
}
|
|
32
22
|
main().catch((err) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAEpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,wDAAwD;IACxD,OAAO,CAAC,KAAK,CACX,wCAAwC,MAAM,CAAC,UAAU,WAAW,MAAM,CAAC,UAAU,IAAI;QACvF,iBAAiB,MAAM,CAAC,MAAM,EAAE,CACnC,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,iCAAkC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP server factory. Both transports — stdio (`index.ts`) and
|
|
3
|
+
* Streamable HTTP (`http.ts`) — build their server through here, so the two
|
|
4
|
+
* surfaces expose the identical 9 tools and instructions.
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import type { Config } from "./config.js";
|
|
8
|
+
import { ApiClient } from "./api-client.js";
|
|
9
|
+
/** The server-level instructions shown to the AI client. */
|
|
10
|
+
export declare function buildInstructions(config: Config): string;
|
|
11
|
+
/**
|
|
12
|
+
* Create a fully-wired McpServer. Pass a shared ApiClient so multiple HTTP
|
|
13
|
+
* sessions reuse one response cache; omit it for a standalone (stdio) process.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createServer(config: Config, api?: ApiClient): McpServer;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared MCP server factory. Both transports — stdio (`index.ts`) and
|
|
3
|
+
* Streamable HTTP (`http.ts`) — build their server through here, so the two
|
|
4
|
+
* surfaces expose the identical 9 tools and instructions.
|
|
5
|
+
*/
|
|
6
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import { ApiClient } from "./api-client.js";
|
|
8
|
+
import { registerTools } from "./tools.js";
|
|
9
|
+
/** The server-level instructions shown to the AI client. */
|
|
10
|
+
export function buildInstructions(config) {
|
|
11
|
+
return (`This server provides real-time transit information for ${config.agencyName}.` +
|
|
12
|
+
(config.agencyDescription ? ` ${config.agencyDescription}` : "") +
|
|
13
|
+
` Use the tools to look up bus stops, schedules, routes, live vehicle positions, ` +
|
|
14
|
+
`and service alerts. Always use the tools for schedule and stop data — never guess ` +
|
|
15
|
+
`times. Note: realtime tools (get_service_alerts, get_live_vehicles) returning an ` +
|
|
16
|
+
`empty result is normal and means "nothing active right now," not "no service."`);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a fully-wired McpServer. Pass a shared ApiClient so multiple HTTP
|
|
20
|
+
* sessions reuse one response cache; omit it for a standalone (stdio) process.
|
|
21
|
+
*/
|
|
22
|
+
export function createServer(config, api = new ApiClient(config)) {
|
|
23
|
+
const server = new McpServer({ name: "gtfs-pro-transit", version: "1.0.0" }, { instructions: buildInstructions(config) });
|
|
24
|
+
registerTools(server, api);
|
|
25
|
+
return server;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,4DAA4D;AAC5D,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,OAAO,CACL,0DAA0D,MAAM,CAAC,UAAU,GAAG;QAC9E,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,kFAAkF;QAClF,oFAAoF;QACpF,mFAAmF;QACnF,gFAAgF,CACjF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,MAAiB,IAAI,SAAS,CAAC,MAAM,CAAC;IACjF,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,EAC9C,EAAE,YAAY,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAC5C,CAAC;IACF,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtfs-pro-mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Model Context Protocol server for any WP GTFS Pro transit site. Lets AI assistants query bus stops, schedules, routes, live vehicle positions, and service alerts from an agency's live GTFS data.",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Model Context Protocol server for any WP GTFS Pro transit site. Lets AI assistants query bus stops, schedules, routes, live vehicle positions, and service alerts from an agency's live GTFS data. Runs locally (stdio) or as a hosted remote connector (Streamable HTTP).",
|
|
5
5
|
"license": "GPL-2.0-or-later",
|
|
6
6
|
"author": "Digital Mountaineers",
|
|
7
7
|
"homepage": "https://github.com/digital-mountaineers/gtfs-pro-mcp#readme",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
],
|
|
27
27
|
"type": "module",
|
|
28
28
|
"bin": {
|
|
29
|
-
"gtfs-pro-mcp": "dist/index.js"
|
|
29
|
+
"gtfs-pro-mcp": "dist/index.js",
|
|
30
|
+
"gtfs-pro-mcp-http": "dist/http.js"
|
|
30
31
|
},
|
|
31
32
|
"files": [
|
|
32
33
|
"dist",
|
|
@@ -41,13 +42,16 @@
|
|
|
41
42
|
"build": "tsc",
|
|
42
43
|
"watch": "tsc --watch",
|
|
43
44
|
"start": "node dist/index.js",
|
|
45
|
+
"start:http": "node dist/http.js",
|
|
44
46
|
"prepublishOnly": "npm run build"
|
|
45
47
|
},
|
|
46
48
|
"dependencies": {
|
|
47
49
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
50
|
+
"express": "^5.1.0",
|
|
48
51
|
"zod": "^3.23.8"
|
|
49
52
|
},
|
|
50
53
|
"devDependencies": {
|
|
54
|
+
"@types/express": "^5.0.0",
|
|
51
55
|
"@types/node": "^22.10.0",
|
|
52
56
|
"typescript": "^5.7.0"
|
|
53
57
|
}
|