@ikeytz/maps-mcp 1.0.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/CHANGELOG.md +6 -0
- package/LICENSE +5 -0
- package/README.md +53 -0
- package/bin/ikeytz-maps-mcp.js +7 -0
- package/package.json +29 -0
- package/src/cli.js +225 -0
- package/src/proxy.js +123 -0
- package/src/tools-catalog.json +103 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @ikeytz/maps-mcp
|
|
2
|
+
|
|
3
|
+
CLI + stdio-Proxy für **maps.ikeytz.com/mcp**. Anderes Paket als `@ikeytz/mcp` (www).
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|--|--|
|
|
7
|
+
| Bin | `ikeytz-maps-mcp` |
|
|
8
|
+
| `mcpName` | `com.ikeytz/maps` |
|
|
9
|
+
| Remote | `https://maps.ikeytz.com/mcp` |
|
|
10
|
+
| Protocol | `2025-11-25` |
|
|
11
|
+
|
|
12
|
+
**Publish (npm) = MAPS-E3**, noch nicht. Lokal aus diesem Repo:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node packages/maps-mcp/bin/ikeytz-maps-mcp.js --version
|
|
16
|
+
node packages/maps-mcp/bin/ikeytz-maps-mcp.js list
|
|
17
|
+
node packages/maps-mcp/bin/ikeytz-maps-mcp.js get_service_area --slug=pattonville
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Nach Publish:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i -g @ikeytz/maps-mcp
|
|
24
|
+
ikeytz-maps-mcp --version
|
|
25
|
+
npx -y @ikeytz/maps-mcp help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Env (nicht `IKEYTZ_MCP_URL`):
|
|
29
|
+
|
|
30
|
+
| Variable | Default |
|
|
31
|
+
|----------|---------|
|
|
32
|
+
| `IKEYTZ_MAPS_MCP_URL` | `https://maps.ikeytz.com/mcp` |
|
|
33
|
+
| `IKEYTZ_MAPS_MCP_PROTOCOL` | `2025-11-25` |
|
|
34
|
+
| `IKEYTZ_MAPS_MCP_TIMEOUT_MS` | `15000` |
|
|
35
|
+
|
|
36
|
+
Ohne Args → stdio (Cursor/Claude):
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"ikeytz-maps": {
|
|
42
|
+
"command": "npx",
|
|
43
|
+
"args": ["-y", "@ikeytz/maps-mcp"]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Lokal vor Publish: `"command": "node"`, `"args": ["…/packages/maps-mcp/bin/ikeytz-maps-mcp.js"]`.
|
|
50
|
+
|
|
51
|
+
www bleibt zweiter Eintrag → `@ikeytz/mcp` / `https://www.ikeytz.com/mcp`.
|
|
52
|
+
|
|
53
|
+
Falsch: `ikeytz-mcp get_service_area --slug=pattonville` (das ist www).
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ikeytz/maps-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"mcpName": "com.ikeytz/maps",
|
|
5
|
+
"description": "Read/Link MCP CLI for maps.ikeytz.com. Not @ikeytz/mcp.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"ikeytz-maps-mcp": "bin/ikeytz-maps-mcp.js"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=18"
|
|
15
|
+
},
|
|
16
|
+
"license": "LicenseRef-ikeytz-terms",
|
|
17
|
+
"files": [
|
|
18
|
+
"bin",
|
|
19
|
+
"src",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"README.md",
|
|
22
|
+
"CHANGELOG.md"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://vmd199268.contaboserver.net/ikeytz-geo/ikeytz-geo-stack.git",
|
|
27
|
+
"directory": "packages/maps-mcp"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { callTool, mapsMcpUrl, mapsRpc, packageVersion, showMcpCommand, toolByName, toolNames } from "./proxy.js";
|
|
3
|
+
|
|
4
|
+
const TOOL_FLAGS = ["slug", "plz", "name", "which", "offset", "limit"];
|
|
5
|
+
|
|
6
|
+
const HELP = `ikeytz-maps-mcp ${packageVersion()}
|
|
7
|
+
Remote: ${mapsMcpUrl()}
|
|
8
|
+
Nur maps. Nicht @ikeytz/mcp / www.
|
|
9
|
+
|
|
10
|
+
Ohne Args stdio-Proxy (Cursor/Claude)
|
|
11
|
+
help | --help diese Hilfe
|
|
12
|
+
--version Version
|
|
13
|
+
update npm i -g @ikeytz/maps-mcp@latest
|
|
14
|
+
list 7 Tools (offline)
|
|
15
|
+
describe <tool> Schema (offline)
|
|
16
|
+
call <tool> … wie <tool> …
|
|
17
|
+
<tool> Payload von maps /mcp
|
|
18
|
+
<tool> -h Args (offline)
|
|
19
|
+
<tool> --show-mcp-command | --show-mcp-befehl
|
|
20
|
+
<tool> --raw volles JSON-RPC
|
|
21
|
+
<tool> --json '{…}'
|
|
22
|
+
|
|
23
|
+
Tools:
|
|
24
|
+
list_service_areas
|
|
25
|
+
get_service_area --slug=… | --plz=… | --name=…
|
|
26
|
+
get_geo_office
|
|
27
|
+
get_contact
|
|
28
|
+
get_discovery --which=llms|llms-orte-geo|ai-plugin|…
|
|
29
|
+
get_llms_mcp_server
|
|
30
|
+
get_llms_mcp_web
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
function parseArgv(argv) {
|
|
34
|
+
const flags = {};
|
|
35
|
+
const positionals = [];
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const a = argv[i];
|
|
38
|
+
if (a === "--raw") flags.raw = true;
|
|
39
|
+
else if (a === "-h" || a === "--help") flags.help = true;
|
|
40
|
+
else if (a === "--version") flags.version = true;
|
|
41
|
+
else if (a === "--show-mcp-command" || a === "--show-mcp-befehl") flags.showMcp = true;
|
|
42
|
+
else if (a === "--json") flags.json = argv[++i] || "";
|
|
43
|
+
else if (a.startsWith("--json=")) flags.json = a.slice(7);
|
|
44
|
+
else if (a.startsWith("--")) {
|
|
45
|
+
const eq = a.indexOf("=");
|
|
46
|
+
if (eq > 0) flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
47
|
+
else {
|
|
48
|
+
const key = a.slice(2);
|
|
49
|
+
const next = argv[i + 1];
|
|
50
|
+
if (next && !next.startsWith("-")) {
|
|
51
|
+
flags[key] = next;
|
|
52
|
+
i += 1;
|
|
53
|
+
} else flags[key] = true;
|
|
54
|
+
}
|
|
55
|
+
} else positionals.push(a);
|
|
56
|
+
}
|
|
57
|
+
return { flags, positionals };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function argsFromFlags(flags) {
|
|
61
|
+
const args = {};
|
|
62
|
+
if (flags.json) Object.assign(args, JSON.parse(flags.json));
|
|
63
|
+
for (const key of TOOL_FLAGS) {
|
|
64
|
+
if (flags[key] != null && flags[key] !== true) {
|
|
65
|
+
args[key] = key === "offset" || key === "limit" ? Number(flags[key]) : String(flags[key]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return args;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function printPayload(rpc, raw) {
|
|
72
|
+
if (raw) {
|
|
73
|
+
process.stdout.write(`${JSON.stringify(rpc, null, 2)}\n`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const data = rpc?.result?.structuredContent ?? rpc?.result ?? rpc;
|
|
77
|
+
process.stdout.write(`${JSON.stringify(data, null, 2)}\n`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function readStdioMessage(buf) {
|
|
81
|
+
const text = buf.toString("utf8");
|
|
82
|
+
const headerEnd = text.indexOf("\r\n\r\n");
|
|
83
|
+
const altEnd = text.indexOf("\n\n");
|
|
84
|
+
if (headerEnd >= 0 || (altEnd >= 0 && /content-length:/i.test(text.slice(0, altEnd + 2)))) {
|
|
85
|
+
const split = headerEnd >= 0 ? headerEnd : altEnd;
|
|
86
|
+
const sep = headerEnd >= 0 ? 4 : 2;
|
|
87
|
+
const header = text.slice(0, split);
|
|
88
|
+
const m = header.match(/content-length:\s*(\d+)/i);
|
|
89
|
+
if (!m) return null;
|
|
90
|
+
const len = Number(m[1]);
|
|
91
|
+
const start = split + sep;
|
|
92
|
+
const body = Buffer.from(text, "utf8").subarray(start);
|
|
93
|
+
if (body.length < len) return null;
|
|
94
|
+
const json = JSON.parse(body.subarray(0, len).toString("utf8"));
|
|
95
|
+
return { json, rest: body.subarray(len) };
|
|
96
|
+
}
|
|
97
|
+
const nl = text.indexOf("\n");
|
|
98
|
+
if (nl < 0) return null;
|
|
99
|
+
const line = text.slice(0, nl).trim();
|
|
100
|
+
const rest = Buffer.from(text.slice(nl + 1), "utf8");
|
|
101
|
+
if (!line) return { json: null, rest };
|
|
102
|
+
return { json: JSON.parse(line), rest };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function writeStdio(msg) {
|
|
106
|
+
const json = JSON.stringify(msg);
|
|
107
|
+
const body = Buffer.from(json, "utf8");
|
|
108
|
+
process.stdout.write(`Content-Length: ${body.length}\r\n\r\n`);
|
|
109
|
+
process.stdout.write(body);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function runStdioProxy() {
|
|
113
|
+
let sessionId = "";
|
|
114
|
+
let buf = Buffer.alloc(0);
|
|
115
|
+
process.stdin.on("data", (chunk) => {
|
|
116
|
+
buf = Buffer.concat([buf, chunk]);
|
|
117
|
+
(async () => {
|
|
118
|
+
while (true) {
|
|
119
|
+
let parsed;
|
|
120
|
+
try {
|
|
121
|
+
parsed = readStdioMessage(buf);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
writeStdio({ jsonrpc: "2.0", id: null, error: { code: -32700, message: String(err.message || err) } });
|
|
124
|
+
buf = Buffer.alloc(0);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
if (!parsed) break;
|
|
128
|
+
buf = parsed.rest;
|
|
129
|
+
if (!parsed.json) continue;
|
|
130
|
+
const msg = parsed.json;
|
|
131
|
+
const method = msg.method;
|
|
132
|
+
const id = msg.id;
|
|
133
|
+
try {
|
|
134
|
+
if (method === "initialize") {
|
|
135
|
+
const out = await mapsRpc("initialize", msg.params || {}, { id: id ?? 1 });
|
|
136
|
+
sessionId = out.sessionId || sessionId;
|
|
137
|
+
writeStdio(out.json);
|
|
138
|
+
} else if (method === "notifications/initialized" || method === "initialized") {
|
|
139
|
+
const out = await mapsRpc("notifications/initialized", msg.params || {}, {
|
|
140
|
+
notification: true,
|
|
141
|
+
sessionId,
|
|
142
|
+
});
|
|
143
|
+
sessionId = out.sessionId || sessionId;
|
|
144
|
+
if (id !== undefined) writeStdio({ jsonrpc: "2.0", id, result: {} });
|
|
145
|
+
} else if (id === undefined) {
|
|
146
|
+
await mapsRpc(method, msg.params || {}, { notification: true, sessionId });
|
|
147
|
+
} else {
|
|
148
|
+
const out = await mapsRpc(method, msg.params || {}, { id, sessionId });
|
|
149
|
+
sessionId = out.sessionId || sessionId;
|
|
150
|
+
writeStdio(out.json);
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
if (id !== undefined) {
|
|
154
|
+
writeStdio({ jsonrpc: "2.0", id, error: { code: -32000, message: String(err.message || err) } });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
})();
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function main(argv) {
|
|
163
|
+
const { flags, positionals } = parseArgv(argv);
|
|
164
|
+
|
|
165
|
+
if (flags.version && positionals.length === 0) {
|
|
166
|
+
process.stdout.write(`${packageVersion()}\n`);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (argv.length === 0) {
|
|
170
|
+
await runStdioProxy();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const cmd = positionals[0] || "";
|
|
175
|
+
if (flags.help && positionals.length === 0) {
|
|
176
|
+
process.stdout.write(HELP);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (cmd === "help" || cmd === "--help") {
|
|
180
|
+
process.stdout.write(HELP);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (cmd === "update") {
|
|
184
|
+
await new Promise((resolve, reject) => {
|
|
185
|
+
const child = spawn("npm", ["i", "-g", "@ikeytz/maps-mcp@latest"], { stdio: "inherit" });
|
|
186
|
+
child.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`npm exit ${code}`))));
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (cmd === "list") {
|
|
191
|
+
process.stdout.write(`${toolNames().join("\n")}\n`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (cmd === "describe") {
|
|
195
|
+
const name = positionals[1];
|
|
196
|
+
const tool = toolByName(name);
|
|
197
|
+
if (!tool) {
|
|
198
|
+
console.error(`unknown tool: ${name || "(fehlt)"}`);
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
process.stdout.write(`${JSON.stringify(tool, null, 2)}\n`);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const toolName = cmd === "call" ? positionals[1] : cmd;
|
|
207
|
+
const tool = toolByName(toolName);
|
|
208
|
+
if (!tool) {
|
|
209
|
+
console.error(`unknown command: ${cmd}\n`);
|
|
210
|
+
process.stdout.write(HELP);
|
|
211
|
+
process.exitCode = 1;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (flags.help) {
|
|
215
|
+
process.stdout.write(`${tool.name}\n${tool.description}\n${JSON.stringify(tool.inputSchema, null, 2)}\n`);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const args = argsFromFlags(flags);
|
|
219
|
+
if (flags.showMcp) {
|
|
220
|
+
process.stdout.write(showMcpCommand(toolName, args));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const rpc = await callTool(toolName, args);
|
|
224
|
+
printPayload(rpc, flags.raw);
|
|
225
|
+
}
|
package/src/proxy.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
+
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
7
|
+
export const CATALOG = JSON.parse(readFileSync(join(root, "src/tools-catalog.json"), "utf8"));
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_URL = "https://maps.ikeytz.com/mcp";
|
|
10
|
+
export const DEFAULT_PROTOCOL = "2025-11-25";
|
|
11
|
+
|
|
12
|
+
export function mapsMcpUrl() {
|
|
13
|
+
return process.env.IKEYTZ_MAPS_MCP_URL || DEFAULT_URL;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function mapsMcpProtocol() {
|
|
17
|
+
return process.env.IKEYTZ_MAPS_MCP_PROTOCOL || DEFAULT_PROTOCOL;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function mapsMcpTimeoutMs() {
|
|
21
|
+
const n = Number(process.env.IKEYTZ_MAPS_MCP_TIMEOUT_MS || 15000);
|
|
22
|
+
return Number.isFinite(n) && n > 0 ? n : 15000;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function packageVersion() {
|
|
26
|
+
return pkg.version;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function toolByName(name) {
|
|
30
|
+
return (CATALOG.tools || []).find((t) => t.name === name) || null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function toolNames() {
|
|
34
|
+
return (CATALOG.tools || []).map((t) => t.name);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function mapsRpc(method, params, { id = 1, sessionId, notification = false } = {}) {
|
|
38
|
+
const url = mapsMcpUrl();
|
|
39
|
+
if (url.includes("geo.ikeytz.com") || url.includes("www.ikeytz.com/mcp")) {
|
|
40
|
+
throw new Error("IKEYTZ_MAPS_MCP_URL muss maps.ikeytz.com/mcp sein");
|
|
41
|
+
}
|
|
42
|
+
const body = notification
|
|
43
|
+
? { jsonrpc: "2.0", method, params: params || {} }
|
|
44
|
+
: { jsonrpc: "2.0", id, method, params: params || {} };
|
|
45
|
+
const headers = {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
Accept: "application/json, text/event-stream",
|
|
48
|
+
"MCP-Protocol-Version": mapsMcpProtocol(),
|
|
49
|
+
};
|
|
50
|
+
if (sessionId) headers["Mcp-Session-Id"] = sessionId;
|
|
51
|
+
const res = await fetch(url, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers,
|
|
54
|
+
body: JSON.stringify(body),
|
|
55
|
+
signal: AbortSignal.timeout(mapsMcpTimeoutMs()),
|
|
56
|
+
});
|
|
57
|
+
const nextSession = res.headers.get("mcp-session-id") || sessionId || "";
|
|
58
|
+
if (notification) {
|
|
59
|
+
return { sessionId: nextSession, status: res.status, json: null };
|
|
60
|
+
}
|
|
61
|
+
const json = await res.json();
|
|
62
|
+
return { sessionId: nextSession, status: res.status, json };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function withSession(fn) {
|
|
66
|
+
const init = await mapsRpc("initialize", {
|
|
67
|
+
protocolVersion: mapsMcpProtocol(),
|
|
68
|
+
capabilities: {},
|
|
69
|
+
clientInfo: { name: "ikeytz-maps-mcp", version: packageVersion() },
|
|
70
|
+
});
|
|
71
|
+
if (init.json?.error) throw new Error(init.json.error.message || "initialize failed");
|
|
72
|
+
const sessionId = init.sessionId;
|
|
73
|
+
await mapsRpc("notifications/initialized", {}, { notification: true, sessionId });
|
|
74
|
+
return fn(sessionId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function callTool(name, args = {}) {
|
|
78
|
+
return withSession(async (sessionId) => {
|
|
79
|
+
const out = await mapsRpc("tools/call", { name, arguments: args }, { id: 2, sessionId });
|
|
80
|
+
if (out.json?.error) {
|
|
81
|
+
const err = new Error(out.json.error.message || "tools/call failed");
|
|
82
|
+
err.rpc = out.json;
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
return out.json;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function showMcpCommand(name, args = {}) {
|
|
90
|
+
const url = mapsMcpUrl();
|
|
91
|
+
const proto = mapsMcpProtocol();
|
|
92
|
+
const payload = JSON.stringify({
|
|
93
|
+
jsonrpc: "2.0",
|
|
94
|
+
id: 2,
|
|
95
|
+
method: "tools/call",
|
|
96
|
+
params: { name, arguments: args },
|
|
97
|
+
});
|
|
98
|
+
return `# 1a) Session-ID holen
|
|
99
|
+
SID=$(curl -sS -D - -o /tmp/ikeytz-maps-mcp-init.json -X POST '${url}' \\
|
|
100
|
+
-H 'Content-Type: application/json' \\
|
|
101
|
+
-H 'Accept: application/json' \\
|
|
102
|
+
-H 'MCP-Protocol-Version: ${proto}' \\
|
|
103
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"${proto}","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' \\
|
|
104
|
+
| awk -F': ' 'tolower($1)=="mcp-session-id"{gsub(/\\r/,"",$2); print $2; exit}')
|
|
105
|
+
echo "SID=$SID"
|
|
106
|
+
|
|
107
|
+
# 1b) initialized
|
|
108
|
+
curl -sS -X POST '${url}' \\
|
|
109
|
+
-H 'Content-Type: application/json' \\
|
|
110
|
+
-H 'Accept: application/json' \\
|
|
111
|
+
-H 'MCP-Protocol-Version: ${proto}' \\
|
|
112
|
+
-H "Mcp-Session-Id: $SID" \\
|
|
113
|
+
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}' >/dev/null
|
|
114
|
+
|
|
115
|
+
# 2) Tool
|
|
116
|
+
curl -sS -X POST '${url}' \\
|
|
117
|
+
-H 'Content-Type: application/json' \\
|
|
118
|
+
-H 'Accept: application/json' \\
|
|
119
|
+
-H 'MCP-Protocol-Version: ${proto}' \\
|
|
120
|
+
-H "Mcp-Session-Id: $SID" \\
|
|
121
|
+
-d '${payload}'
|
|
122
|
+
`;
|
|
123
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tools": [
|
|
3
|
+
{
|
|
4
|
+
"name": "list_service_areas",
|
|
5
|
+
"description": "Alle 52 Einsatzgebiete auf maps.ikeytz.com (Punkte, keine Polygone).",
|
|
6
|
+
"inputSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {}
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "get_service_area",
|
|
13
|
+
"description": "Ein Einsatzgebiet. Lookup: slug → plz (erster Treffer) → name (Substring).",
|
|
14
|
+
"inputSchema": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"slug": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"plz": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
"name": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "get_geo_office",
|
|
31
|
+
"description": "Gewerbesitz Ludwigsburg. Kein Walk-in.",
|
|
32
|
+
"inputSchema": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "get_contact",
|
|
39
|
+
"description": "NAP: Handy, Festnetz, Fax, E-Mail, WhatsApp, Adresse.",
|
|
40
|
+
"inputSchema": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"properties": {}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "get_discovery",
|
|
47
|
+
"description": "1:1 Spiegel einer maps-Discovery-Datei (llms, robots, plugin, sitemap, …).",
|
|
48
|
+
"inputSchema": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"properties": {
|
|
51
|
+
"which": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"enum": [
|
|
54
|
+
"llms",
|
|
55
|
+
"llms-full",
|
|
56
|
+
"llms-index",
|
|
57
|
+
"llms-keywords",
|
|
58
|
+
"llms-serp",
|
|
59
|
+
"llms-impressum-kontakt",
|
|
60
|
+
"llms-orte-geo",
|
|
61
|
+
"llms-urheberrecht",
|
|
62
|
+
"llms-copyright",
|
|
63
|
+
"llms-mcp-server",
|
|
64
|
+
"llms-mcp-web",
|
|
65
|
+
"robots",
|
|
66
|
+
"sitemap-txt",
|
|
67
|
+
"sitemap-xml",
|
|
68
|
+
"ai-txt",
|
|
69
|
+
"ai-plugin",
|
|
70
|
+
"answer-engine",
|
|
71
|
+
"ai-catalog"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"offset": {
|
|
75
|
+
"type": "integer"
|
|
76
|
+
},
|
|
77
|
+
"limit": {
|
|
78
|
+
"type": "integer"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"required": [
|
|
82
|
+
"which"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "get_llms_mcp_server",
|
|
88
|
+
"description": "Katalog llms-mcp-server.txt",
|
|
89
|
+
"inputSchema": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"properties": {}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "get_llms_mcp_web",
|
|
96
|
+
"description": "Katalog llms-mcp-web.txt",
|
|
97
|
+
"inputSchema": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"properties": {}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|