@fluttersdk/mcp 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 +98 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# @fluttersdk/mcp
|
|
2
|
+
|
|
3
|
+
HTTP-to-stdio bridge for the [FlutterSDK Docs MCP server](https://mcp.fluttersdk.com/).
|
|
4
|
+
|
|
5
|
+
The upstream server at `mcp.fluttersdk.com` speaks the Streamable HTTP MCP transport.
|
|
6
|
+
This bridge wraps it with a stdio transport so clients that do not support
|
|
7
|
+
Streamable HTTP natively (Claude Desktop, older Codex CLI, any shell-based MCP host)
|
|
8
|
+
can connect to it without modification.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
Use this bridge when your MCP client:
|
|
13
|
+
|
|
14
|
+
- Only supports stdio MCP transport (e.g. Claude Desktop, older Cursor versions).
|
|
15
|
+
- Cannot talk to HTTP-based MCP servers directly.
|
|
16
|
+
- Needs a proxy in front of the upstream for allowlist control.
|
|
17
|
+
|
|
18
|
+
If your client natively supports Streamable HTTP, point it directly at
|
|
19
|
+
`https://mcp.fluttersdk.com/` instead.
|
|
20
|
+
|
|
21
|
+
## Install and run
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx @fluttersdk/mcp
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The bridge starts a local stdio MCP server. It does not connect to the upstream
|
|
28
|
+
until the first `tools/list` or `tools/call` request arrives (lazy connect).
|
|
29
|
+
|
|
30
|
+
## Environment variables
|
|
31
|
+
|
|
32
|
+
| Variable | Default | Description |
|
|
33
|
+
|----------|---------|-------------|
|
|
34
|
+
| `FLUTTERSDK_MCP_URL` | `https://mcp.fluttersdk.com/` | Upstream MCP server URL |
|
|
35
|
+
| `BRIDGE_ALLOW_TOOLS` | `search-docs` | Comma-separated list of tool names to expose. Use `*` for unrestricted access. |
|
|
36
|
+
|
|
37
|
+
### Examples
|
|
38
|
+
|
|
39
|
+
Expose only the default `search-docs` tool (default behavior):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx @fluttersdk/mcp
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Expose all tools the upstream provides:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
BRIDGE_ALLOW_TOOLS=* npx @fluttersdk/mcp
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Point at a local upstream during development:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
FLUTTERSDK_MCP_URL=http://localhost:8000/ npx @fluttersdk/mcp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Claude Desktop configuration
|
|
58
|
+
|
|
59
|
+
Add the following to your Claude Desktop `claude_desktop_config.json`:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"fluttersdk": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["@fluttersdk/mcp"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
To allow all upstream tools:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"fluttersdk": {
|
|
78
|
+
"command": "npx",
|
|
79
|
+
"args": ["@fluttersdk/mcp"],
|
|
80
|
+
"env": {
|
|
81
|
+
"BRIDGE_ALLOW_TOOLS": "*"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Available tools
|
|
89
|
+
|
|
90
|
+
The upstream server exposes one tool by default (and the bridge allowlist matches it):
|
|
91
|
+
|
|
92
|
+
| Tool | Description |
|
|
93
|
+
|------|-------------|
|
|
94
|
+
| `search-docs` | Search Flutter and Dart documentation. Accepts `queries`, `packages`, `version`, and `token_limit` parameters. |
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Filters a list of tools by the allowlist string.
|
|
5
|
+
*
|
|
6
|
+
* @param tools - The full tool list returned by the upstream server.
|
|
7
|
+
* @param allowlist - Comma-separated tool names, or "*" for unrestricted access.
|
|
8
|
+
* @returns The filtered subset of tools.
|
|
9
|
+
*/
|
|
10
|
+
export declare function filterTools(tools: Tool[], allowlist: string): Tool[];
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAMA,OAAO,EAAiD,KAAK,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAK9G;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,CAUpE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
const UPSTREAM_URL = process.env["FLUTTERSDK_MCP_URL"] ?? "https://mcp.fluttersdk.com/";
|
|
8
|
+
const ALLOW_TOOLS = process.env["BRIDGE_ALLOW_TOOLS"] ?? "search-docs";
|
|
9
|
+
/**
|
|
10
|
+
* Filters a list of tools by the allowlist string.
|
|
11
|
+
*
|
|
12
|
+
* @param tools - The full tool list returned by the upstream server.
|
|
13
|
+
* @param allowlist - Comma-separated tool names, or "*" for unrestricted access.
|
|
14
|
+
* @returns The filtered subset of tools.
|
|
15
|
+
*/
|
|
16
|
+
export function filterTools(tools, allowlist) {
|
|
17
|
+
if (allowlist.trim() === "*") {
|
|
18
|
+
return tools;
|
|
19
|
+
}
|
|
20
|
+
const allowed = new Set(allowlist.split(",").map((name) => name.trim()).filter(Boolean));
|
|
21
|
+
return tools.filter((tool) => allowed.has(tool.name));
|
|
22
|
+
}
|
|
23
|
+
const server = new Server({ name: "fluttersdk-bridge", version: "1.1.0" }, { capabilities: { tools: {} } });
|
|
24
|
+
// Lazily initialized upstream client and cached tool list.
|
|
25
|
+
let upstreamClient = null;
|
|
26
|
+
let cachedTools = null;
|
|
27
|
+
async function getUpstreamClient() {
|
|
28
|
+
if (upstreamClient !== null) {
|
|
29
|
+
return upstreamClient;
|
|
30
|
+
}
|
|
31
|
+
const client = new Client({ name: "fluttersdk-bridge-client", version: "1.1.0" });
|
|
32
|
+
const transport = new StreamableHTTPClientTransport(new URL(UPSTREAM_URL));
|
|
33
|
+
await client.connect(transport);
|
|
34
|
+
upstreamClient = client;
|
|
35
|
+
return client;
|
|
36
|
+
}
|
|
37
|
+
async function getFilteredTools() {
|
|
38
|
+
if (cachedTools !== null) {
|
|
39
|
+
return cachedTools;
|
|
40
|
+
}
|
|
41
|
+
const client = await getUpstreamClient();
|
|
42
|
+
const result = await client.listTools();
|
|
43
|
+
cachedTools = filterTools(result.tools, ALLOW_TOOLS);
|
|
44
|
+
return cachedTools;
|
|
45
|
+
}
|
|
46
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
47
|
+
const tools = await getFilteredTools();
|
|
48
|
+
return { tools };
|
|
49
|
+
});
|
|
50
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
51
|
+
const tools = await getFilteredTools();
|
|
52
|
+
const allowed = tools.some((tool) => tool.name === request.params.name);
|
|
53
|
+
if (!allowed) {
|
|
54
|
+
throw new Error(`Tool "${request.params.name}" is not available through this bridge.`);
|
|
55
|
+
}
|
|
56
|
+
const client = await getUpstreamClient();
|
|
57
|
+
return client.callTool(request.params);
|
|
58
|
+
});
|
|
59
|
+
const transport = new StdioServerTransport();
|
|
60
|
+
await server.connect(transport);
|
|
61
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluttersdk/mcp",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "HTTP↔stdio bridge for the FlutterSDK Docs MCP server (mcp.fluttersdk.com)",
|
|
5
|
+
"author": "Anilcan Cakir <anilcan.cakir@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"fluttersdk-mcp": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"lint": "eslint src/",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"start": "node dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
24
|
+
"zod": "^3.23.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^22.0.0",
|
|
28
|
+
"typescript": "^5.6.0",
|
|
29
|
+
"vitest": "^2.0.0"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18.0.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/fluttersdk/ai",
|
|
40
|
+
"directory": "mcps/fluttersdk-mcp"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"mcp",
|
|
44
|
+
"flutter",
|
|
45
|
+
"fluttersdk",
|
|
46
|
+
"bridge",
|
|
47
|
+
"stdio",
|
|
48
|
+
"streamable-http"
|
|
49
|
+
]
|
|
50
|
+
}
|