asynthetic 0.1.0 → 0.1.1
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 +116 -46
- package/dist/index.js +131 -153
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +13 -0
- package/dist/server.js +166 -0
- package/dist/server.js.map +1 -0
- package/package.json +21 -1
package/README.md
CHANGED
|
@@ -1,93 +1,163 @@
|
|
|
1
|
-
# Asynthetic
|
|
1
|
+
# Asynthetic
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Verified migration maps for AI coding agents, served over MCP.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
LLMs suffer from temporal drift: training data mixes many versions of a library, so an agent confidently writes v4 syntax into a v5 codebase. Asynthetic is an MCP (Model Context Protocol) server that tells agents **exactly what breaks between two versions of a library and how to fix it** — from hand-curated, source-cited migration maps instead of stale model memory.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
> Context7 tells the agent what the current API is. **Asynthetic tells the agent what changed and how to migrate.**
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
Every migration map is hand-curated from authoritative sources only — official migration guides, GitHub releases, and framework blogs — and every map carries:
|
|
12
|
+
|
|
13
|
+
- ordered breaking changes with **before/after code snippets**
|
|
14
|
+
- a `category` per change (`signature-change`, `removal`, `rename`, `behavior-change`, `config-change`, `import-change`, `deprecation`)
|
|
15
|
+
- deprecations with replacement symbols and removal timelines
|
|
16
|
+
- **`source_urls` citations** and a **`last_verified` date**
|
|
17
|
+
|
|
18
|
+
Maps are never LLM-generated. A map that would be wrong is worse than no map, so when nothing verified matches a query, the server says so explicitly and instructs the agent **not** to fabricate migration steps.
|
|
8
19
|
|
|
9
20
|
## Tools
|
|
10
21
|
|
|
11
|
-
| Tool |
|
|
22
|
+
| Tool | Returns |
|
|
12
23
|
|---|---|
|
|
13
|
-
| `get_migration(package, from_version, to_version, ecosystem?)` |
|
|
14
|
-
| `get_breaking_changes(package, version, ecosystem?)` | Breaking changes introduced when upgrading **to**
|
|
24
|
+
| `get_migration(package, from_version, to_version, ecosystem?)` | The full migration map for the requested upgrade window |
|
|
25
|
+
| `get_breaking_changes(package, version, ecosystem?)` | Breaking changes introduced when upgrading **to** a version |
|
|
15
26
|
| `check_compatibility(...)` | Stub — always returns `implemented: false` (planned) |
|
|
16
27
|
|
|
17
|
-
Version
|
|
28
|
+
Version arguments accept concrete versions (`14.2.35`), partial versions (`14`), or SemVer ranges (`^14.2.0`, `~4.3.0`, `15.x`). Resolution is exact-first, then SemVer-aware, and always disclosed in the response via `match_type`, `resolved_via` (`exact_string` / `semver_range` / `major_version`), and a `match_note`.
|
|
18
29
|
|
|
19
|
-
##
|
|
30
|
+
## Current coverage
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
| Package | Migration | Breaking changes |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `@modelcontextprotocol/sdk` | 1.x → 2.0 | 21 |
|
|
35
|
+
| `ai` (Vercel AI SDK) | 4.x → 5.0 | 23 |
|
|
36
|
+
| `next` (Next.js) | 14 → 15 | 17 |
|
|
37
|
+
|
|
38
|
+
Coverage is deliberately narrow and deep: fast-moving AI and JavaScript-ecosystem frameworks, curated for correctness over breadth.
|
|
25
39
|
|
|
26
|
-
|
|
40
|
+
## Quick start
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
### Hosted server (HTTP)
|
|
29
43
|
|
|
30
44
|
```sh
|
|
31
|
-
|
|
45
|
+
claude mcp add --transport http asynthetic https://asynthetic.up.railway.app/mcp
|
|
32
46
|
```
|
|
33
47
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- `get_migration` with `package: @modelcontextprotocol/sdk`, `from_version: 1.29.0`, `to_version: 2.0.0-beta.2` → full map, `match_type: "exact"`
|
|
37
|
-
- `get_migration` with `from_version: 1.20.0`, `to_version: 2.0.0` → same map with a `match_note` disclosure
|
|
38
|
-
- `get_migration` with `package: left-pad` → `found: false` + guidance
|
|
48
|
+
Or in any client that takes a JSON MCP config:
|
|
39
49
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"asynthetic": {
|
|
54
|
+
"url": "https://asynthetic.up.railway.app/mcp"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
44
58
|
```
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
### Local (stdio via npm)
|
|
47
61
|
|
|
48
62
|
```sh
|
|
49
|
-
claude mcp add asynthetic --
|
|
63
|
+
claude mcp add asynthetic -- npx -y asynthetic
|
|
50
64
|
```
|
|
51
65
|
|
|
52
|
-
Cursor (`.cursor/mcp.json`) or any client using JSON config:
|
|
53
|
-
|
|
54
66
|
```json
|
|
55
67
|
{
|
|
56
68
|
"mcpServers": {
|
|
57
69
|
"asynthetic": {
|
|
58
|
-
"command": "
|
|
59
|
-
"args": ["
|
|
70
|
+
"command": "npx",
|
|
71
|
+
"args": ["-y", "asynthetic"]
|
|
60
72
|
}
|
|
61
73
|
}
|
|
62
74
|
}
|
|
63
75
|
```
|
|
64
76
|
|
|
65
|
-
|
|
77
|
+
The published package bundles the curated maps, so local stdio mode works offline with no database or configuration.
|
|
78
|
+
|
|
79
|
+
## HTTP endpoints
|
|
80
|
+
|
|
81
|
+
When the `PORT` environment variable is set, the server runs as an HTTP service (otherwise it speaks stdio):
|
|
82
|
+
|
|
83
|
+
| Endpoint | Transport |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `POST` / `GET` / `DELETE` `/mcp` | **Streamable HTTP** — the current MCP transport; use this from modern clients |
|
|
86
|
+
| `GET /sse` + `POST /messages` | Legacy HTTP+SSE — compatibility for older clients (protocol 2024-11-05) |
|
|
87
|
+
| `GET /` | Health/info JSON (name, version, active store, endpoints) |
|
|
88
|
+
|
|
89
|
+
Sessions are managed per client with `Mcp-Session-Id` (Streamable HTTP) or `sessionId` (legacy SSE); each session gets an isolated server instance.
|
|
90
|
+
|
|
91
|
+
## Response shape
|
|
92
|
+
|
|
93
|
+
Successful lookups return structured JSON with full verification metadata:
|
|
94
|
+
|
|
95
|
+
```jsonc
|
|
96
|
+
{
|
|
97
|
+
"found": true,
|
|
98
|
+
"match_type": "semver-range",
|
|
99
|
+
"resolved_via": "semver_range",
|
|
100
|
+
"match_note": "Resolved via SemVer range processing: ...",
|
|
101
|
+
"migration": {
|
|
102
|
+
"package": "next",
|
|
103
|
+
"from_version": "14.2.35",
|
|
104
|
+
"to_version": "15.0.0",
|
|
105
|
+
"breaking_changes": [ /* ordered, with before/after code */ ],
|
|
106
|
+
"deprecations": [ /* symbol, replacement, removal timeline */ ],
|
|
107
|
+
"source_urls": ["https://nextjs.org/docs/app/guides/upgrading/version-15"],
|
|
108
|
+
"last_verified": "2026-07-03",
|
|
109
|
+
"status": "draft"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Missed lookups return `found: false`, an explicit anti-hallucination instruction, and the list of maps that do exist.
|
|
66
115
|
|
|
67
|
-
##
|
|
116
|
+
## Self-hosting
|
|
68
117
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
118
|
+
```sh
|
|
119
|
+
git clone https://github.com/asyntheticai/asynthetic.git
|
|
120
|
+
cd asynthetic
|
|
121
|
+
npm install
|
|
122
|
+
npm run build
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
| Variable | Effect |
|
|
126
|
+
|---|---|
|
|
127
|
+
| *(none)* | Serves the bundled JSON maps from `data/maps/` — zero-config mode |
|
|
128
|
+
| `SUPABASE_URL` + `SUPABASE_ANON_KEY` | Serves from Postgres (run `schema/schema.sql`, then `npm run seed`) |
|
|
129
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | Needed by `npm run seed` only |
|
|
130
|
+
| `PORT` | Switches from stdio to the HTTP transports above |
|
|
131
|
+
| `MIGRATION_DATA_DIR` | Overrides the local maps directory |
|
|
132
|
+
|
|
133
|
+
The server never crashes on missing configuration — absent database credentials fall back to the bundled maps with a note on stderr.
|
|
134
|
+
|
|
135
|
+
## Development
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
npm run smoke # build + 17-check end-to-end suite (stdio, Streamable HTTP, and SSE)
|
|
139
|
+
npm run inspect # build + launch @modelcontextprotocol/inspector against the server
|
|
140
|
+
npm run dev # run from source over stdio
|
|
141
|
+
```
|
|
73
142
|
|
|
74
|
-
|
|
143
|
+
### Adding a migration map
|
|
75
144
|
|
|
76
|
-
1. Curate from **official sources only** (
|
|
77
|
-
2. Add a JSON file under `data/maps/<ecosystem>/<package
|
|
78
|
-
3. Set `status: "draft"` until
|
|
79
|
-
4. `npm run seed` to
|
|
145
|
+
1. Curate from **official sources only** (changelogs, GitHub releases, migration guides). Record every URL.
|
|
146
|
+
2. Add a JSON file under `data/maps/<ecosystem>/<package>/` following the schema in `src/types/migration-map.ts`. Files are Zod-validated at load and seed time; invalid maps are skipped with a warning, never served.
|
|
147
|
+
3. Set `status: "draft"` until snippets are verified against real code, then `"verified"`. Mark superseded maps `"stale"` (excluded from serving) instead of deleting them.
|
|
148
|
+
4. `npm run seed` to sync Postgres, if used.
|
|
80
149
|
|
|
81
150
|
## Project layout
|
|
82
151
|
|
|
83
152
|
```
|
|
84
153
|
schema/schema.sql Postgres tables (migrations, breaking_changes, deprecations)
|
|
85
154
|
src/types/migration-map.ts TypeScript types + Zod validator for map JSON
|
|
86
|
-
src/store/
|
|
87
|
-
src/
|
|
155
|
+
src/store/ Store interface, Supabase + local-file backends, SemVer resolver
|
|
156
|
+
src/server.ts MCP server factory (tool registration)
|
|
157
|
+
src/index.ts Entry point: stdio or HTTP by environment
|
|
88
158
|
data/maps/ Hand-curated migration maps (source of truth)
|
|
89
159
|
scripts/seed.ts Load data/maps into Supabase
|
|
90
|
-
scripts/smoke.ts End-to-end
|
|
160
|
+
scripts/smoke.ts End-to-end test suite
|
|
91
161
|
```
|
|
92
162
|
|
|
93
|
-
Built
|
|
163
|
+
Built with TypeScript, the official [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk) (v1.x stable line), Zod, Express, and Supabase. Node.js 22+.
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Asynthetic — MCP server
|
|
3
|
+
* Asynthetic — MCP server entry point with dual transport.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Transport is chosen by environment:
|
|
6
|
+
* - PORT set (Railway/cloud): Express HTTP server exposing the modern
|
|
7
|
+
* Streamable HTTP endpoint (POST/GET/DELETE /mcp) plus the legacy
|
|
8
|
+
* HTTP+SSE endpoints (GET /sse + POST /messages) for older clients.
|
|
9
|
+
* - No PORT: stdio, so local use in Claude Code / Cursor / MCP Inspector
|
|
10
|
+
* is completely unaffected.
|
|
7
11
|
*
|
|
8
|
-
* stdout is the protocol channel — all logging goes to stderr
|
|
12
|
+
* In stdio mode stdout is the protocol channel — all logging goes to stderr.
|
|
9
13
|
*/
|
|
10
|
-
import {
|
|
14
|
+
import { randomUUID } from 'node:crypto';
|
|
15
|
+
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
11
16
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
|
-
import {
|
|
17
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
18
|
+
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
19
|
+
import express from 'express';
|
|
20
|
+
import { buildServer, SERVER_NAME, SERVER_VERSION } from './server.js';
|
|
13
21
|
import { createStore } from './store/create-store.js';
|
|
14
|
-
import { interpretDescriptor, majorOf, normalizeVersion, resolveMigration, resolvedViaOf, toSummary, } from './store/store.js';
|
|
15
22
|
// Load .env when present (dev convenience, no dotenv dependency).
|
|
16
23
|
try {
|
|
17
24
|
process.loadEnvFile();
|
|
@@ -20,160 +27,131 @@ catch {
|
|
|
20
27
|
// no .env file — fine, env vars may come from the MCP client config
|
|
21
28
|
}
|
|
22
29
|
const store = createStore();
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
'
|
|
26
|
-
function jsonResult(payload, isError = false) {
|
|
27
|
-
return {
|
|
28
|
-
content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
|
|
29
|
-
...(isError ? { isError: true } : {}),
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function storeError(err) {
|
|
33
|
-
console.error('[asynthetic] Store error:', err);
|
|
34
|
-
return jsonResult({ error: `Store lookup failed: ${err instanceof Error ? err.message : String(err)}` }, true);
|
|
30
|
+
async function startStdio() {
|
|
31
|
+
await buildServer(store).connect(new StdioServerTransport());
|
|
32
|
+
console.error('[asynthetic] Ready on stdio');
|
|
35
33
|
}
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const resolved = resolveMigration(maps, from_version, to_version);
|
|
63
|
-
if (!resolved) {
|
|
64
|
-
const available = maps.length > 0 ? maps.map(toSummary) : await store.listMaps();
|
|
65
|
-
return jsonResult({
|
|
66
|
-
found: false,
|
|
67
|
-
requested,
|
|
68
|
-
message: NOT_FOUND_GUIDANCE,
|
|
69
|
-
available_maps: available,
|
|
34
|
+
async function startHttp(port) {
|
|
35
|
+
const app = express();
|
|
36
|
+
app.use(express.json());
|
|
37
|
+
// --- Modern Streamable HTTP transport (one session per client) ---
|
|
38
|
+
const streamableTransports = {};
|
|
39
|
+
app.post('/mcp', async (req, res) => {
|
|
40
|
+
try {
|
|
41
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
42
|
+
const existing = sessionId ? streamableTransports[sessionId] : undefined;
|
|
43
|
+
if (existing) {
|
|
44
|
+
await existing.handleRequest(req, res, req.body);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (sessionId || !isInitializeRequest(req.body)) {
|
|
48
|
+
res.status(400).json({
|
|
49
|
+
jsonrpc: '2.0',
|
|
50
|
+
error: { code: -32000, message: 'Bad Request: no valid session. Send an initialize request first.' },
|
|
51
|
+
id: null,
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const transport = new StreamableHTTPServerTransport({
|
|
56
|
+
sessionIdGenerator: () => randomUUID(),
|
|
57
|
+
onsessioninitialized: (sid) => {
|
|
58
|
+
streamableTransports[sid] = transport;
|
|
59
|
+
},
|
|
70
60
|
});
|
|
61
|
+
transport.onclose = () => {
|
|
62
|
+
const sid = transport.sessionId;
|
|
63
|
+
if (sid)
|
|
64
|
+
delete streamableTransports[sid];
|
|
65
|
+
};
|
|
66
|
+
await buildServer(store).connect(transport);
|
|
67
|
+
await transport.handleRequest(req, res, req.body);
|
|
71
68
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
version: z
|
|
104
|
-
.string()
|
|
105
|
-
.min(1)
|
|
106
|
-
.describe('The version (or SemVer range) whose breaking changes you want, e.g. "2.0.0", "^15.0.0"'),
|
|
107
|
-
ecosystem: ecosystemArg,
|
|
108
|
-
},
|
|
109
|
-
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
110
|
-
}, async ({ package: pkg, version, ecosystem }) => {
|
|
111
|
-
const requested = { package: pkg, ecosystem, version };
|
|
112
|
-
try {
|
|
113
|
-
const target = interpretDescriptor(version);
|
|
114
|
-
const maps = await store.getMapsForPackage(ecosystem, pkg);
|
|
115
|
-
const matching = target === null ? [] : maps.filter((m) => majorOf(m.to_version) === target.major);
|
|
116
|
-
if (matching.length === 0) {
|
|
117
|
-
const available = maps.length > 0 ? maps.map(toSummary) : await store.listMaps();
|
|
118
|
-
return jsonResult({
|
|
119
|
-
found: false,
|
|
120
|
-
requested,
|
|
121
|
-
message: NOT_FOUND_GUIDANCE,
|
|
122
|
-
available_maps: available,
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.error('[asynthetic] /mcp error:', err);
|
|
71
|
+
if (!res.headersSent) {
|
|
72
|
+
res.status(500).json({
|
|
73
|
+
jsonrpc: '2.0',
|
|
74
|
+
error: { code: -32603, message: 'Internal server error' },
|
|
75
|
+
id: null,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// GET /mcp = server->client notification stream; DELETE /mcp = session end.
|
|
81
|
+
const handleSessionRequest = async (req, res) => {
|
|
82
|
+
const sessionId = req.headers['mcp-session-id'];
|
|
83
|
+
const transport = sessionId ? streamableTransports[sessionId] : undefined;
|
|
84
|
+
if (!transport) {
|
|
85
|
+
res.status(400).send('Invalid or missing Mcp-Session-Id');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
await transport.handleRequest(req, res);
|
|
89
|
+
};
|
|
90
|
+
app.get('/mcp', handleSessionRequest);
|
|
91
|
+
app.delete('/mcp', handleSessionRequest);
|
|
92
|
+
// --- Legacy HTTP+SSE transport (protocol 2024-11-05) for older clients ---
|
|
93
|
+
const sseTransports = {};
|
|
94
|
+
app.get('/sse', async (_req, res) => {
|
|
95
|
+
try {
|
|
96
|
+
const transport = new SSEServerTransport('/messages', res);
|
|
97
|
+
sseTransports[transport.sessionId] = transport;
|
|
98
|
+
res.on('close', () => {
|
|
99
|
+
delete sseTransports[transport.sessionId];
|
|
123
100
|
});
|
|
101
|
+
await buildServer(store).connect(transport);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
console.error('[asynthetic] /sse error:', err);
|
|
105
|
+
if (!res.headersSent)
|
|
106
|
+
res.status(500).send('Internal server error');
|
|
124
107
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
108
|
+
});
|
|
109
|
+
app.post('/messages', async (req, res) => {
|
|
110
|
+
const sessionId = req.query.sessionId;
|
|
111
|
+
const transport = sessionId ? sseTransports[sessionId] : undefined;
|
|
112
|
+
if (!transport) {
|
|
113
|
+
res.status(400).send('No transport found for sessionId');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
await transport.handlePostMessage(req, res, req.body);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
console.error('[asynthetic] /messages error:', err);
|
|
121
|
+
if (!res.headersSent)
|
|
122
|
+
res.status(500).send('Internal server error');
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// Health/info endpoint for platform checks and humans.
|
|
126
|
+
app.get('/', (_req, res) => {
|
|
127
|
+
res.json({
|
|
128
|
+
name: SERVER_NAME,
|
|
129
|
+
version: SERVER_VERSION,
|
|
130
|
+
store: store.describe(),
|
|
131
|
+
transports: { streamable_http: '/mcp', sse_legacy: '/sse' },
|
|
147
132
|
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
version_a: z.string().min(1),
|
|
162
|
-
package_b: z.string().min(1),
|
|
163
|
-
version_b: z.string().min(1),
|
|
164
|
-
ecosystem: ecosystemArg,
|
|
165
|
-
},
|
|
166
|
-
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
167
|
-
}, async () => jsonResult({
|
|
168
|
-
implemented: false,
|
|
169
|
-
message: 'Cross-package compatibility lookup is planned but not yet available. This response contains no ' +
|
|
170
|
-
'compatibility data — do not treat it as evidence that the packages are (or are not) compatible.',
|
|
171
|
-
}));
|
|
133
|
+
});
|
|
134
|
+
const httpServer = app.listen(port, () => {
|
|
135
|
+
console.error(`[asynthetic] Ready on HTTP :${port} (Streamable HTTP at /mcp, legacy SSE at /sse)`);
|
|
136
|
+
});
|
|
137
|
+
// Railway sends SIGTERM on redeploy/scale-down — close cleanly.
|
|
138
|
+
const shutdown = () => {
|
|
139
|
+
console.error('[asynthetic] Shutting down');
|
|
140
|
+
httpServer.close(() => process.exit(0));
|
|
141
|
+
setTimeout(() => process.exit(0), 5000).unref();
|
|
142
|
+
};
|
|
143
|
+
process.on('SIGTERM', shutdown);
|
|
144
|
+
process.on('SIGINT', shutdown);
|
|
145
|
+
}
|
|
172
146
|
async function main() {
|
|
173
147
|
console.error(`[asynthetic] Starting (store: ${store.describe()})`);
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
148
|
+
const port = process.env.PORT ? Number.parseInt(process.env.PORT, 10) : Number.NaN;
|
|
149
|
+
if (Number.isFinite(port)) {
|
|
150
|
+
await startHttp(port);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
await startStdio();
|
|
154
|
+
}
|
|
177
155
|
}
|
|
178
156
|
main().catch((err) => {
|
|
179
157
|
console.error('[asynthetic] Fatal:', err);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asynthetic — MCP server factory.
|
|
3
|
+
*
|
|
4
|
+
* builds a fully-registered McpServer instance. A factory (rather than a
|
|
5
|
+
* module-level singleton) because HTTP mode serves many concurrent sessions
|
|
6
|
+
* and a Protocol instance binds to exactly one transport; stdio mode simply
|
|
7
|
+
* builds one.
|
|
8
|
+
*/
|
|
9
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { type MigrationStore } from './store/store.js';
|
|
11
|
+
export declare const SERVER_NAME = "asynthetic";
|
|
12
|
+
export declare const SERVER_VERSION = "0.1.0-beta";
|
|
13
|
+
export declare function buildServer(store: MigrationStore): McpServer;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asynthetic — MCP server factory.
|
|
3
|
+
*
|
|
4
|
+
* builds a fully-registered McpServer instance. A factory (rather than a
|
|
5
|
+
* module-level singleton) because HTTP mode serves many concurrent sessions
|
|
6
|
+
* and a Protocol instance binds to exactly one transport; stdio mode simply
|
|
7
|
+
* builds one.
|
|
8
|
+
*/
|
|
9
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { interpretDescriptor, majorOf, normalizeVersion, resolveMigration, resolvedViaOf, toSummary, } from './store/store.js';
|
|
12
|
+
export const SERVER_NAME = 'asynthetic';
|
|
13
|
+
export const SERVER_VERSION = '0.1.0-beta';
|
|
14
|
+
const NOT_FOUND_GUIDANCE = 'No verified migration map exists for this request. Do NOT fabricate migration steps from model memory — ' +
|
|
15
|
+
'consult the official changelog / release notes for this package instead.';
|
|
16
|
+
function jsonResult(payload, isError = false) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
|
|
19
|
+
...(isError ? { isError: true } : {}),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function storeError(err) {
|
|
23
|
+
console.error('[asynthetic] Store error:', err);
|
|
24
|
+
return jsonResult({ error: `Store lookup failed: ${err instanceof Error ? err.message : String(err)}` }, true);
|
|
25
|
+
}
|
|
26
|
+
const packageArg = z.string().min(1).describe('Package name as published, e.g. "@modelcontextprotocol/sdk"');
|
|
27
|
+
const ecosystemArg = z.string().default('npm').describe('Package ecosystem (default "npm")');
|
|
28
|
+
export function buildServer(store) {
|
|
29
|
+
const server = new McpServer({ name: SERVER_NAME, version: SERVER_VERSION });
|
|
30
|
+
server.registerTool('get_migration', {
|
|
31
|
+
title: 'Get migration map',
|
|
32
|
+
description: 'Returns the verified migration map for upgrading a package between two versions: ordered breaking ' +
|
|
33
|
+
'changes with before/after code, deprecations, source-citation URLs, and a last_verified date. ' +
|
|
34
|
+
'Accepts concrete versions or SemVer ranges (e.g. "^14.2.0", "~14.1.0", "15.x"); non-exact lookups ' +
|
|
35
|
+
'resolve to the covering map and disclose how via match_type/resolved_via/match_note. ' +
|
|
36
|
+
'If found=false, no verified data exists — do not guess.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
package: packageArg,
|
|
39
|
+
from_version: z
|
|
40
|
+
.string()
|
|
41
|
+
.min(1)
|
|
42
|
+
.describe('Version or SemVer range currently in use, e.g. "1.29.0", "^14.2.0", "1.x"'),
|
|
43
|
+
to_version: z
|
|
44
|
+
.string()
|
|
45
|
+
.min(1)
|
|
46
|
+
.describe('Version or SemVer range upgrading to, e.g. "2.0.0", "^15.0.0", "2.x"'),
|
|
47
|
+
ecosystem: ecosystemArg,
|
|
48
|
+
},
|
|
49
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
50
|
+
}, async ({ package: pkg, from_version, to_version, ecosystem }) => {
|
|
51
|
+
const requested = { package: pkg, ecosystem, from_version, to_version };
|
|
52
|
+
try {
|
|
53
|
+
const maps = await store.getMapsForPackage(ecosystem, pkg);
|
|
54
|
+
const resolved = resolveMigration(maps, from_version, to_version);
|
|
55
|
+
if (!resolved) {
|
|
56
|
+
const available = maps.length > 0 ? maps.map(toSummary) : await store.listMaps();
|
|
57
|
+
return jsonResult({
|
|
58
|
+
found: false,
|
|
59
|
+
requested,
|
|
60
|
+
message: NOT_FOUND_GUIDANCE,
|
|
61
|
+
available_maps: available,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const { map, match_type } = resolved;
|
|
65
|
+
const match_note = match_type === 'exact'
|
|
66
|
+
? undefined
|
|
67
|
+
: match_type === 'semver-range'
|
|
68
|
+
? `Resolved via SemVer range processing: the requested window ${from_version} -> ${to_version} ` +
|
|
69
|
+
`falls inside the map verified for ${map.from_version} -> ${map.to_version}. ` +
|
|
70
|
+
'Details specific to intermediate minor/patch versions may not be covered.'
|
|
71
|
+
: `No map exists for exactly ${from_version} -> ${to_version}; returning the map verified for ` +
|
|
72
|
+
`${map.from_version} -> ${map.to_version} (same major-version jump). ` +
|
|
73
|
+
'Details specific to intermediate minor/patch versions may not be covered.';
|
|
74
|
+
return jsonResult({
|
|
75
|
+
found: true,
|
|
76
|
+
requested,
|
|
77
|
+
match_type,
|
|
78
|
+
resolved_via: resolvedViaOf(match_type),
|
|
79
|
+
...(match_note ? { match_note } : {}),
|
|
80
|
+
migration: map,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
return storeError(err);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
server.registerTool('get_breaking_changes', {
|
|
88
|
+
title: 'Get breaking changes in a version',
|
|
89
|
+
description: 'Returns the breaking changes introduced when upgrading TO the given version of a package (matched by ' +
|
|
90
|
+
'major version against curated migration maps), with source citations and last_verified dates. ' +
|
|
91
|
+
'Accepts concrete versions or SemVer ranges ("15", "^15.0.0", "15.x"); resolution is disclosed via ' +
|
|
92
|
+
'match_type/resolved_via. If found=false, no verified data exists — do not guess.',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
package: packageArg,
|
|
95
|
+
version: z
|
|
96
|
+
.string()
|
|
97
|
+
.min(1)
|
|
98
|
+
.describe('The version (or SemVer range) whose breaking changes you want, e.g. "2.0.0", "^15.0.0"'),
|
|
99
|
+
ecosystem: ecosystemArg,
|
|
100
|
+
},
|
|
101
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
102
|
+
}, async ({ package: pkg, version, ecosystem }) => {
|
|
103
|
+
const requested = { package: pkg, ecosystem, version };
|
|
104
|
+
try {
|
|
105
|
+
const target = interpretDescriptor(version);
|
|
106
|
+
const maps = await store.getMapsForPackage(ecosystem, pkg);
|
|
107
|
+
const matching = target === null ? [] : maps.filter((m) => majorOf(m.to_version) === target.major);
|
|
108
|
+
if (matching.length === 0) {
|
|
109
|
+
const available = maps.length > 0 ? maps.map(toSummary) : await store.listMaps();
|
|
110
|
+
return jsonResult({
|
|
111
|
+
found: false,
|
|
112
|
+
requested,
|
|
113
|
+
message: NOT_FOUND_GUIDANCE,
|
|
114
|
+
available_maps: available,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return jsonResult({
|
|
118
|
+
found: true,
|
|
119
|
+
requested,
|
|
120
|
+
results: matching.map((map) => {
|
|
121
|
+
const match_type = normalizeVersion(map.to_version) === normalizeVersion(version)
|
|
122
|
+
? 'exact'
|
|
123
|
+
: target.kind === 'range'
|
|
124
|
+
? 'semver-range'
|
|
125
|
+
: 'major-version';
|
|
126
|
+
return {
|
|
127
|
+
from_version: map.from_version,
|
|
128
|
+
to_version: map.to_version,
|
|
129
|
+
match_type,
|
|
130
|
+
resolved_via: resolvedViaOf(match_type),
|
|
131
|
+
status: map.status,
|
|
132
|
+
last_verified: map.last_verified,
|
|
133
|
+
source_urls: map.source_urls,
|
|
134
|
+
summary: map.summary,
|
|
135
|
+
breaking_changes: map.breaking_changes,
|
|
136
|
+
deprecations: map.deprecations,
|
|
137
|
+
};
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
return storeError(err);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
// Stub per brief §7/§11: declared so agents can discover it, but explicitly
|
|
146
|
+
// returns "not implemented" — it must never look like real compatibility data.
|
|
147
|
+
server.registerTool('check_compatibility', {
|
|
148
|
+
title: 'Check cross-package compatibility (not yet implemented)',
|
|
149
|
+
description: 'PLANNED: known compatibility issues between two package versions. Currently returns implemented=false ' +
|
|
150
|
+
'and no data. Do not infer compatibility (or incompatibility) from this response.',
|
|
151
|
+
inputSchema: {
|
|
152
|
+
package_a: z.string().min(1),
|
|
153
|
+
version_a: z.string().min(1),
|
|
154
|
+
package_b: z.string().min(1),
|
|
155
|
+
version_b: z.string().min(1),
|
|
156
|
+
ecosystem: ecosystemArg,
|
|
157
|
+
},
|
|
158
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
159
|
+
}, async () => jsonResult({
|
|
160
|
+
implemented: false,
|
|
161
|
+
message: 'Cross-package compatibility lookup is planned but not yet available. This response contains no ' +
|
|
162
|
+
'compatibility data — do not treat it as evidence that the packages are (or are not) compatible.',
|
|
163
|
+
}));
|
|
164
|
+
return server;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "asynthetic",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Asynthetic — MCP server that gives AI coding agents verified migration maps for fast-moving libraries: exactly what breaks between two versions and how to fix it.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"mcp-server",
|
|
9
|
+
"migration",
|
|
10
|
+
"breaking-changes",
|
|
11
|
+
"upgrade",
|
|
12
|
+
"semver",
|
|
13
|
+
"ai-agents"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/asyntheticai/asynthetic.git"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/asyntheticai/asynthetic#readme",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/asyntheticai/asynthetic/issues"
|
|
22
|
+
},
|
|
5
23
|
"type": "module",
|
|
6
24
|
"engines": {
|
|
7
25
|
"node": ">=22"
|
|
@@ -25,10 +43,12 @@
|
|
|
25
43
|
"dependencies": {
|
|
26
44
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
27
45
|
"@supabase/supabase-js": "^2.49.0",
|
|
46
|
+
"express": "^5.2.1",
|
|
28
47
|
"semver": "^7.8.5",
|
|
29
48
|
"zod": "^3.25.76"
|
|
30
49
|
},
|
|
31
50
|
"devDependencies": {
|
|
51
|
+
"@types/express": "^5.0.6",
|
|
32
52
|
"@types/node": "^22.10.0",
|
|
33
53
|
"@types/semver": "^7.7.1",
|
|
34
54
|
"tsx": "^4.19.0",
|