fa-mcp-sdk 0.4.141 → 0.11.2
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 +5 -0
- package/cli-template/.dockerignore +16 -0
- package/cli-template/.gitlab-ci.yml +135 -0
- package/cli-template/AGENTS.md +1 -0
- package/cli-template/CHANGELOG.md +64 -0
- package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +27 -4
- package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +195 -0
- package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +172 -9
- package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +170 -12
- package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +158 -8
- package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +67 -6
- package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +31 -15
- package/cli-template/FA-MCP-SDK-DOC/10-mcp-apps.md +1 -1
- package/cli-template/FA-MCP-SDK-DOC/11-public-contract.md +342 -0
- package/cli-template/README.md +37 -0
- package/cli-template/deploy/docker/.env.example +10 -0
- package/cli-template/deploy/docker/Dockerfile +44 -0
- package/cli-template/deploy/docker/Dockerfile.local +29 -0
- package/cli-template/deploy/docker/README.md +94 -0
- package/cli-template/deploy/docker/config/local.docker.yaml +14 -0
- package/cli-template/deploy/docker/docker-compose.yml +31 -0
- package/cli-template/deploy/gitlab-runner/.env.example +16 -0
- package/cli-template/deploy/gitlab-runner/README.md +65 -0
- package/cli-template/deploy/gitlab-runner/config/config.toml.template +26 -0
- package/cli-template/deploy/gitlab-runner/docker-compose.yml +39 -0
- package/cli-template/deploy/gitlab-runner/entrypoint.sh +27 -0
- package/cli-template/deploy/gitlab-runner/start.sh +47 -0
- package/cli-template/gitignore +96 -95
- package/cli-template/package.json +1 -1
- package/config/_local.yaml +73 -11
- package/config/custom-environment-variables.yaml +102 -0
- package/config/default.yaml +164 -11
- package/config/local.yaml +20 -19
- package/dist/core/_types_/config.d.ts +119 -0
- package/dist/core/_types_/config.d.ts.map +1 -1
- package/dist/core/_types_/types.d.ts +137 -4
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/agent-tester/agent-tester-router.d.ts.map +1 -1
- package/dist/core/agent-tester/agent-tester-router.js +25 -11
- package/dist/core/agent-tester/agent-tester-router.js.map +1 -1
- package/dist/core/agent-tester/services/TesterMcpClientService.d.ts.map +1 -1
- package/dist/core/agent-tester/services/TesterMcpClientService.js +6 -4
- package/dist/core/agent-tester/services/TesterMcpClientService.js.map +1 -1
- package/dist/core/auth/admin-auth.js +4 -4
- package/dist/core/auth/admin-auth.js.map +1 -1
- package/dist/core/auth/agent-tester-auth.d.ts +1 -1
- package/dist/core/auth/agent-tester-auth.d.ts.map +1 -1
- package/dist/core/auth/agent-tester-auth.js +8 -4
- package/dist/core/auth/agent-tester-auth.js.map +1 -1
- package/dist/core/auth/auth-profile.d.ts +38 -0
- package/dist/core/auth/auth-profile.d.ts.map +1 -0
- package/dist/core/auth/auth-profile.js +101 -0
- package/dist/core/auth/auth-profile.js.map +1 -0
- package/dist/core/auth/jwt-v2.d.ts +27 -0
- package/dist/core/auth/jwt-v2.d.ts.map +1 -0
- package/dist/core/auth/jwt-v2.js +180 -0
- package/dist/core/auth/jwt-v2.js.map +1 -0
- package/dist/core/auth/jwt.d.ts +27 -13
- package/dist/core/auth/jwt.d.ts.map +1 -1
- package/dist/core/auth/jwt.js +36 -13
- package/dist/core/auth/jwt.js.map +1 -1
- package/dist/core/auth/key-resolver.d.ts +74 -0
- package/dist/core/auth/key-resolver.d.ts.map +1 -0
- package/dist/core/auth/key-resolver.js +330 -0
- package/dist/core/auth/key-resolver.js.map +1 -0
- package/dist/core/auth/middleware.d.ts.map +1 -1
- package/dist/core/auth/middleware.js +66 -0
- package/dist/core/auth/middleware.js.map +1 -1
- package/dist/core/auth/multi-auth.d.ts +1 -1
- package/dist/core/auth/multi-auth.d.ts.map +1 -1
- package/dist/core/auth/multi-auth.js +7 -7
- package/dist/core/auth/multi-auth.js.map +1 -1
- package/dist/core/auth/token-generator/server.js +4 -4
- package/dist/core/auth/token-generator/server.js.map +1 -1
- package/dist/core/auth/types.d.ts +5 -0
- package/dist/core/auth/types.d.ts.map +1 -1
- package/dist/core/db/pg-db.d.ts +7 -0
- package/dist/core/db/pg-db.d.ts.map +1 -1
- package/dist/core/db/pg-db.js +54 -3
- package/dist/core/db/pg-db.js.map +1 -1
- package/dist/core/errors/BaseMcpError.d.ts +21 -1
- package/dist/core/errors/BaseMcpError.d.ts.map +1 -1
- package/dist/core/errors/BaseMcpError.js +20 -1
- package/dist/core/errors/BaseMcpError.js.map +1 -1
- package/dist/core/errors/ValidationError.d.ts +5 -0
- package/dist/core/errors/ValidationError.d.ts.map +1 -1
- package/dist/core/errors/ValidationError.js +6 -1
- package/dist/core/errors/ValidationError.js.map +1 -1
- package/dist/core/errors/errors.d.ts +31 -3
- package/dist/core/errors/errors.d.ts.map +1 -1
- package/dist/core/errors/errors.js +86 -6
- package/dist/core/errors/errors.js.map +1 -1
- package/dist/core/errors/specific-errors.d.ts +54 -0
- package/dist/core/errors/specific-errors.d.ts.map +1 -0
- package/dist/core/errors/specific-errors.js +82 -0
- package/dist/core/errors/specific-errors.js.map +1 -0
- package/dist/core/index.d.ts +10 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/init-mcp-server.d.ts.map +1 -1
- package/dist/core/init-mcp-server.js +39 -0
- package/dist/core/init-mcp-server.js.map +1 -1
- package/dist/core/mcp/create-mcp-server.d.ts +12 -6
- package/dist/core/mcp/create-mcp-server.d.ts.map +1 -1
- package/dist/core/mcp/create-mcp-server.js +592 -33
- package/dist/core/mcp/create-mcp-server.js.map +1 -1
- package/dist/core/mcp/debug-trace.d.ts +3 -1
- package/dist/core/mcp/debug-trace.d.ts.map +1 -1
- package/dist/core/mcp/debug-trace.js +17 -2
- package/dist/core/mcp/debug-trace.js.map +1 -1
- package/dist/core/mcp/deprecation.d.ts +31 -0
- package/dist/core/mcp/deprecation.d.ts.map +1 -0
- package/dist/core/mcp/deprecation.js +96 -0
- package/dist/core/mcp/deprecation.js.map +1 -0
- package/dist/core/mcp/mcp-logging.d.ts +32 -0
- package/dist/core/mcp/mcp-logging.d.ts.map +1 -0
- package/dist/core/mcp/mcp-logging.js +97 -0
- package/dist/core/mcp/mcp-logging.js.map +1 -0
- package/dist/core/mcp/pagination.d.ts +13 -0
- package/dist/core/mcp/pagination.d.ts.map +1 -0
- package/dist/core/mcp/pagination.js +50 -0
- package/dist/core/mcp/pagination.js.map +1 -0
- package/dist/core/mcp/prompts.d.ts +5 -1
- package/dist/core/mcp/prompts.d.ts.map +1 -1
- package/dist/core/mcp/prompts.js +3 -1
- package/dist/core/mcp/prompts.js.map +1 -1
- package/dist/core/mcp/resources.d.ts +9 -0
- package/dist/core/mcp/resources.d.ts.map +1 -1
- package/dist/core/mcp/resources.js +158 -11
- package/dist/core/mcp/resources.js.map +1 -1
- package/dist/core/mcp/server-stdio.d.ts +7 -1
- package/dist/core/mcp/server-stdio.d.ts.map +1 -1
- package/dist/core/mcp/server-stdio.js +8 -3
- package/dist/core/mcp/server-stdio.js.map +1 -1
- package/dist/core/mcp/task-store.d.ts +97 -0
- package/dist/core/mcp/task-store.d.ts.map +1 -0
- package/dist/core/mcp/task-store.js +175 -0
- package/dist/core/mcp/task-store.js.map +1 -0
- package/dist/core/mcp/tool-limits.d.ts +22 -0
- package/dist/core/mcp/tool-limits.d.ts.map +1 -0
- package/dist/core/mcp/tool-limits.js +115 -0
- package/dist/core/mcp/tool-limits.js.map +1 -0
- package/dist/core/mcp/validate-tool-args.d.ts +16 -0
- package/dist/core/mcp/validate-tool-args.d.ts.map +1 -0
- package/dist/core/mcp/validate-tool-args.js +67 -0
- package/dist/core/mcp/validate-tool-args.js.map +1 -0
- package/dist/core/mcp/validate-tool-names.d.ts +11 -0
- package/dist/core/mcp/validate-tool-names.d.ts.map +1 -0
- package/dist/core/mcp/validate-tool-names.js +23 -0
- package/dist/core/mcp/validate-tool-names.js.map +1 -0
- package/dist/core/metrics/metrics.d.ts +45 -0
- package/dist/core/metrics/metrics.d.ts.map +1 -0
- package/dist/core/metrics/metrics.js +119 -0
- package/dist/core/metrics/metrics.js.map +1 -0
- package/dist/core/utils/mask-sensitive.d.ts +44 -0
- package/dist/core/utils/mask-sensitive.d.ts.map +1 -0
- package/dist/core/utils/mask-sensitive.js +64 -0
- package/dist/core/utils/mask-sensitive.js.map +1 -0
- package/dist/core/utils/testing/McpHttpClient.d.ts +8 -33
- package/dist/core/utils/testing/McpHttpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpHttpClient.js +8 -74
- package/dist/core/utils/testing/McpHttpClient.js.map +1 -1
- package/dist/core/utils/testing/McpStreamableHttpClient.d.ts +24 -30
- package/dist/core/utils/testing/McpStreamableHttpClient.d.ts.map +1 -1
- package/dist/core/utils/testing/McpStreamableHttpClient.js +36 -198
- package/dist/core/utils/testing/McpStreamableHttpClient.js.map +1 -1
- package/dist/core/utils/utils.d.ts.map +1 -1
- package/dist/core/utils/utils.js +2 -0
- package/dist/core/utils/utils.js.map +1 -1
- package/dist/core/web/admin-router.js +3 -3
- package/dist/core/web/admin-router.js.map +1 -1
- package/dist/core/web/cors.d.ts +9 -1
- package/dist/core/web/cors.d.ts.map +1 -1
- package/dist/core/web/cors.js +26 -5
- package/dist/core/web/cors.js.map +1 -1
- package/dist/core/web/event-store.d.ts +33 -0
- package/dist/core/web/event-store.d.ts.map +1 -0
- package/dist/core/web/event-store.js +65 -0
- package/dist/core/web/event-store.js.map +1 -0
- package/dist/core/web/oauth-router.d.ts +37 -0
- package/dist/core/web/oauth-router.d.ts.map +1 -0
- package/dist/core/web/oauth-router.js +207 -0
- package/dist/core/web/oauth-router.js.map +1 -0
- package/dist/core/web/request-id.d.ts +44 -0
- package/dist/core/web/request-id.d.ts.map +1 -0
- package/dist/core/web/request-id.js +82 -0
- package/dist/core/web/request-id.js.map +1 -0
- package/dist/core/web/server-http.d.ts.map +1 -1
- package/dist/core/web/server-http.js +322 -182
- package/dist/core/web/server-http.js.map +1 -1
- package/package.json +15 -2
- package/scripts/claude-2-agents-symlink.js +10 -1
- package/scripts/generate-jwt.js +129 -51
- package/src/template/custom-resources.ts +14 -0
- package/src/template/prompts/custom-prompts.ts +4 -0
- package/src/template/tools/handle-tool-call.ts +59 -3
- package/src/template/tools/tools.ts +92 -31
- package/src/tests/mcp/test-http.js +1 -1
- package/src/tests/mcp/test-sse.js +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,11 @@ This framework provides complete infrastructure for building enterprise-grade MC
|
|
|
16
16
|
- **Database Integration**: PostgreSQL with pgvector for vector operations
|
|
17
17
|
- **Service Discovery**: Consul integration for microservices
|
|
18
18
|
- **Rate Limiting**: Configurable rate limiting for all endpoints
|
|
19
|
+
- **Transport Hardening**: Per-tool execution timeout, JSON-RPC request body cap and tool-result truncation —
|
|
20
|
+
all driven by `mcp.limits` in `config/default.yaml`:
|
|
21
|
+
- `mcp.limits.maxPayloadBytes` — max accepted request body (default 1 MiB; JSON-RPC `-32005` / HTTP 413 above)
|
|
22
|
+
- `mcp.limits.maxToolResultBytes` — max serialized tool result (default 10 MiB; truncated with explicit marker)
|
|
23
|
+
- `mcp.limits.toolTimeoutMs` — per-tool execution timeout (default 30 000 ms; JSON-RPC `-32004` / HTTP 504 above)
|
|
19
24
|
- **API Documentation**: Automatic Swagger/OpenAPI generation
|
|
20
25
|
- **Production Logging**: Structured logging with data masking
|
|
21
26
|
- **Configuration Management**: YAML-based with environment overrides
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
stages:
|
|
2
|
+
- lint
|
|
3
|
+
- test-build
|
|
4
|
+
- build-image
|
|
5
|
+
- deploy
|
|
6
|
+
|
|
7
|
+
# ── CI: Merge Request checks ──────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
.node-template: &node-template
|
|
10
|
+
image: node:22-alpine
|
|
11
|
+
tags:
|
|
12
|
+
- docker
|
|
13
|
+
before_script:
|
|
14
|
+
- yarn install --frozen-lockfile
|
|
15
|
+
cache:
|
|
16
|
+
key:
|
|
17
|
+
files:
|
|
18
|
+
- yarn.lock
|
|
19
|
+
paths:
|
|
20
|
+
- node_modules/
|
|
21
|
+
rules:
|
|
22
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
23
|
+
|
|
24
|
+
lint:
|
|
25
|
+
<<: *node-template
|
|
26
|
+
stage: lint
|
|
27
|
+
script:
|
|
28
|
+
- yarn lint
|
|
29
|
+
|
|
30
|
+
test-build:
|
|
31
|
+
<<: *node-template
|
|
32
|
+
stage: test-build
|
|
33
|
+
script:
|
|
34
|
+
- yarn build
|
|
35
|
+
|
|
36
|
+
# ── CD: Build Docker Image ────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
build-image:
|
|
39
|
+
stage: build-image
|
|
40
|
+
image: docker:27
|
|
41
|
+
services:
|
|
42
|
+
- docker:27-dind
|
|
43
|
+
tags:
|
|
44
|
+
- docker
|
|
45
|
+
script:
|
|
46
|
+
- docker compose -f deploy/docker/docker-compose.yml up -d --build --force-recreate app
|
|
47
|
+
rules:
|
|
48
|
+
- if: '$CI_COMMIT_BRANCH == "master"'
|
|
49
|
+
when: manual
|
|
50
|
+
|
|
51
|
+
# ── CD: Deploy ────────────────────────────────────────────────────
|
|
52
|
+
# Замените <SERVER_TAG> на тег вашего сервера, <BRANCH> на целевую ветку,
|
|
53
|
+
# <DEPLOY_DIR> на путь к проекту на сервере.
|
|
54
|
+
|
|
55
|
+
# deploy_<instance>:
|
|
56
|
+
# stage: deploy
|
|
57
|
+
# tags:
|
|
58
|
+
# - <SERVER_TAG>
|
|
59
|
+
# variables:
|
|
60
|
+
# HOST_PORT: {{port}}
|
|
61
|
+
# environment:
|
|
62
|
+
# name: <instance>
|
|
63
|
+
# script:
|
|
64
|
+
# - docker compose -f deploy/docker/docker-compose.yml --env-file .env up -d --build --force-recreate app
|
|
65
|
+
# - |
|
|
66
|
+
# echo "Waiting for health check..."
|
|
67
|
+
# for i in $(seq 1 60); do
|
|
68
|
+
# if docker compose -f deploy/docker/docker-compose.yml exec -T app wget -q -O /dev/null http://localhost:{{port}}/health 2>/dev/null; then
|
|
69
|
+
# echo "Health check passed after ${i}s"
|
|
70
|
+
# break
|
|
71
|
+
# fi
|
|
72
|
+
# if [ "$i" -eq 60 ]; then
|
|
73
|
+
# echo "Health check failed after 60s"
|
|
74
|
+
# docker compose -f deploy/docker/docker-compose.yml logs --tail=50 app
|
|
75
|
+
# exit 1
|
|
76
|
+
# fi
|
|
77
|
+
# sleep 1
|
|
78
|
+
# done
|
|
79
|
+
# - docker compose -f deploy/docker/docker-compose.yml logs --tail=50 app
|
|
80
|
+
# rules:
|
|
81
|
+
# - if: '$CI_COMMIT_BRANCH == "<BRANCH>"'
|
|
82
|
+
# when: manual
|
|
83
|
+
|
|
84
|
+
# stop_<instance>:
|
|
85
|
+
# stage: deploy
|
|
86
|
+
# tags:
|
|
87
|
+
# - <SERVER_TAG>
|
|
88
|
+
# environment:
|
|
89
|
+
# name: <instance>
|
|
90
|
+
# script:
|
|
91
|
+
# - docker compose -f deploy/docker/docker-compose.yml down
|
|
92
|
+
# rules:
|
|
93
|
+
# - if: '$CI_COMMIT_BRANCH == "<BRANCH>"'
|
|
94
|
+
# when: manual
|
|
95
|
+
|
|
96
|
+
# restart_<instance>:
|
|
97
|
+
# stage: deploy
|
|
98
|
+
# tags:
|
|
99
|
+
# - <SERVER_TAG>
|
|
100
|
+
# variables:
|
|
101
|
+
# HOST_PORT: {{port}}
|
|
102
|
+
# environment:
|
|
103
|
+
# name: <instance>
|
|
104
|
+
# script:
|
|
105
|
+
# - docker compose -f deploy/docker/docker-compose.yml --env-file .env restart app
|
|
106
|
+
# - |
|
|
107
|
+
# echo "Waiting for health check..."
|
|
108
|
+
# for i in $(seq 1 60); do
|
|
109
|
+
# if docker compose -f deploy/docker/docker-compose.yml exec -T app wget -q -O /dev/null http://localhost:{{port}}/health 2>/dev/null; then
|
|
110
|
+
# echo "Health check passed after ${i}s"
|
|
111
|
+
# break
|
|
112
|
+
# fi
|
|
113
|
+
# if [ "$i" -eq 60 ]; then
|
|
114
|
+
# echo "Health check failed after 60s"
|
|
115
|
+
# docker compose -f deploy/docker/docker-compose.yml logs --tail=100 app
|
|
116
|
+
# exit 1
|
|
117
|
+
# fi
|
|
118
|
+
# sleep 1
|
|
119
|
+
# done
|
|
120
|
+
# - docker compose -f deploy/docker/docker-compose.yml logs --tail=100 app
|
|
121
|
+
# rules:
|
|
122
|
+
# - if: '$CI_COMMIT_BRANCH == "<BRANCH>"'
|
|
123
|
+
# when: manual
|
|
124
|
+
|
|
125
|
+
# logs_<instance>:
|
|
126
|
+
# stage: deploy
|
|
127
|
+
# tags:
|
|
128
|
+
# - <SERVER_TAG>
|
|
129
|
+
# environment:
|
|
130
|
+
# name: <instance>
|
|
131
|
+
# script:
|
|
132
|
+
# - docker compose -f deploy/docker/docker-compose.yml logs --tail=100 app
|
|
133
|
+
# rules:
|
|
134
|
+
# - if: '$CI_COMMIT_BRANCH == "<BRANCH>"'
|
|
135
|
+
# when: manual
|
package/cli-template/AGENTS.md
CHANGED
|
@@ -131,6 +131,7 @@ Detailed fa-mcp-sdk docs are in `FA-MCP-SDK-DOC/`:
|
|
|
131
131
|
| `08-agent-tester-and-headless-api.md` | Agent Tester, Headless API, structured logging, automated testing, MCP Apps mode (capability negotiation, `appCalls[]`, widget rendering, App Inspector) |
|
|
132
132
|
| `09-database.md` | PostgreSQL sugar layer (`queryMAIN`, `execMAIN`, upserts, `mergeByBatch`), `pgvector`, secondary DBs |
|
|
133
133
|
| `10-mcp-apps.md` | Building / extending MCP Apps (UI-augmented tools) — protocol contract, SDK surface, patterns, pitfalls |
|
|
134
|
+
| `11-public-contract.md` | Formal SDK public contract — transports, endpoints, JWT claims, tool/prompt/resource format, error mapping, headers, semver & deprecation policy |
|
|
134
135
|
|
|
135
136
|
## Development and Testing Through Agent Tester
|
|
136
137
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this MCP server are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project
|
|
6
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Every breaking change
|
|
7
|
+
MUST be tagged with `[BREAKING]`. See
|
|
8
|
+
[FA-MCP-SDK-DOC/11-public-contract.md](FA-MCP-SDK-DOC/11-public-contract.md#8-versioning-policy-171)
|
|
9
|
+
for the MAJOR / MINOR / PATCH rules.
|
|
10
|
+
|
|
11
|
+
## Versioning policy (summary)
|
|
12
|
+
|
|
13
|
+
| Change | Bump |
|
|
14
|
+
|-----------------------------------------------------------------|-------|
|
|
15
|
+
| Removing a tool / prompt / resource | MAJOR |
|
|
16
|
+
| Adding a `required` field to an `inputSchema` | MAJOR |
|
|
17
|
+
| Removing a field from an `outputSchema` | MAJOR |
|
|
18
|
+
| Renaming or removing an HTTP endpoint | MAJOR |
|
|
19
|
+
| Adding a new tool / prompt / resource | MINOR |
|
|
20
|
+
| Adding an optional field to a schema | MINOR |
|
|
21
|
+
| Bug-fix without contract impact | PATCH |
|
|
22
|
+
|
|
23
|
+
## [Unreleased]
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- New tool `<name>` — short description (MINOR).
|
|
28
|
+
- New optional argument `<arg>` on tool `<name>` (MINOR).
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- `<tool_name>` description clarified to mention the default value of `<arg>` (PATCH).
|
|
33
|
+
|
|
34
|
+
### Deprecated
|
|
35
|
+
|
|
36
|
+
- Tool `<old_name>` — replaced by `<new_name>`. Removal scheduled for 2026-08-28
|
|
37
|
+
(≥ 2 MINOR releases or 3 months — whichever comes later, per the public contract). The
|
|
38
|
+
SDK now emits `[DEPRECATED until 2026-08-28, use <new_name>]` on `tools/list` and a
|
|
39
|
+
`logger.warn` the first time per hour an old call lands.
|
|
40
|
+
|
|
41
|
+
### Removed [BREAKING]
|
|
42
|
+
|
|
43
|
+
- Removed deprecated tool `<old_old_name>` (MAJOR). Migration window closed on 2026-05-01.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Race condition in `<tool>` when called concurrently from multiple sessions (PATCH).
|
|
48
|
+
|
|
49
|
+
### Security
|
|
50
|
+
|
|
51
|
+
- Bumped `fa-mcp-sdk` to `^0.8.0` for `X-Request-Id` correlation and `traceparent` propagation.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## [0.1.0] - YYYY-MM-DD
|
|
56
|
+
|
|
57
|
+
Initial release.
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- MCP server scaffolded from `fa-mcp-sdk`.
|
|
62
|
+
- Tools: `<tool>` …
|
|
63
|
+
- Prompts: `agent_brief`, `agent_prompt`.
|
|
64
|
+
- Resources: `project://version`, `use://auth`.
|
|
@@ -13,16 +13,17 @@ npm install fa-mcp-sdk
|
|
|
13
13
|
| File | Content | Read When |
|
|
14
14
|
|------|---------|-----------|
|
|
15
15
|
| [01-getting-started](01-getting-started.md) | `initMcpServer()`, `McpServerData`, `IPromptData`, `IResourceData`, `AppConfig` | Starting new project |
|
|
16
|
-
| [02-1-tools-and-api](02-1-tools-and-api.md) | Tool definitions, `toolHandler`, outbound webhooks, REST API with tsoa, OpenAPI/Swagger | Creating tools, REST endpoints, webhook callbacks |
|
|
17
|
-
| [02-2-prompts-and-resources](02-2-prompts-and-resources.md) | Standard/custom prompts, resources, `requireAuth` | Configuring prompts/resources |
|
|
18
|
-
| [03-configuration](03-configuration.md) | `appConfig`, YAML config, access points
|
|
19
|
-
| [04-authentication](04-authentication.md) | JWT, Basic auth, server tokens, `createAuthMW()`, Token Generator, CLI Token Generator, JWT Generation API | Authentication setup |
|
|
16
|
+
| [02-1-tools-and-api](02-1-tools-and-api.md) | Tool definitions, **snake_case name validation**, **`$schema` 2020-12 + `additionalProperties:false`**, **server-side `arguments` validation**, **`outputSchema` + `structuredContent` mirror**, `toolHandler`, outbound webhooks, REST API with tsoa, OpenAPI/Swagger | Creating tools, REST endpoints, webhook callbacks |
|
|
17
|
+
| [02-2-prompts-and-resources](02-2-prompts-and-resources.md) | Standard/custom prompts, **parameterised prompts (`IPromptArgument[]`)**, resources, **built-in `project://version`, `use://auth`, `<name>://agent/brief\|prompt`**, **opt-in `resources/templates/list` + `resources/subscribe`**, `requireAuth` | Configuring prompts/resources |
|
|
18
|
+
| [03-configuration](03-configuration.md) | `appConfig`, YAML config, access points, cache, **`mcp.limits` (payload/result/timeout)**, **`mcp.pagination`**, **`mcp.resources` (MAY)**, **`mcp.rateLimit.scope` + `maxConcurrentPerSubject` (§14)**, **`webServer.trustProxy`**, **`webServer.tokenCheck.allowQueryToken` (§7.1)**, **/health & /ready**, **CORS hardening**, **MCP error codes** (`-32002…-32005`) | Server configuration, external services, transport-level hardening |
|
|
19
|
+
| [04-authentication](04-authentication.md) | JWT (**4 modes: legacyAesCtr / embedded / localKey / remoteJwks**), Basic auth, server tokens, **OAuth discovery + `/oauth/token` + JWKS**, **`requiredScopes` enforcement (§7.5)**, **`WWW-Authenticate` realm + invalid_token (§7.4)**, **HTTP 403 `forbidden` flag**, `createAuthMW()`, Token Generator, CLI Token Generator (mode-aware), JWT Generation API | Authentication setup |
|
|
20
20
|
| [05-ad-authorization](05-ad-authorization.md) | AD group authorization at HTTP/tool levels | AD group restrictions |
|
|
21
21
|
| [06-utilities](06-utilities.md) | `ServerError`, `normalizeHeaders`, logging, MCP debug switches (`DEBUG=mcp:*`), JSON-lines sink (`mcp.debug.logFile` → `emitTrace`), built-in debug tools (`mcp.debug.builtinTools`), Consul, graceful shutdown | Error handling, utilities, request tracing, post-mortem analysis |
|
|
22
22
|
| [07-testing-and-operations](07-testing-and-operations.md) | Test clients (STDIO, HTTP, SSE, Streamable HTTP); universal `debug-tool` fixture covering every `CallToolResult` shape | Testing, deployment, exercising client code against image/audio/resource/error/delay variants |
|
|
23
23
|
| [08-agent-tester-and-headless-api](08-agent-tester-and-headless-api.md) | Agent Tester, Headless API, structured logging, automated testing, UI `data-testid` reference. **MCP Apps mode**: capability negotiation, `appCalls[]` / `app_calls[]`, widget iframe bridge, App Inspector tab | Agent-driven tool development, CLI automation, UI E2E tests, MCP Apps host for development |
|
|
24
24
|
| [09-database](09-database.md) | PostgreSQL sugar layer (`queryMAIN`, `execMAIN`, `getInsertSqlMAIN`, `getMergeSqlMAIN`, `mergeByBatch`), `pgvector`, secondary DBs | Database access, upserts, batching |
|
|
25
25
|
| [10-mcp-apps](10-mcp-apps.md) | Self-contained digest of the MCP Apps protocol + SDK pinned to `@modelcontextprotocol/ext-apps v1.7.2` (spec 2026-01-26): `ui://` resources, `_meta.ui`, JSON-RPC messages, `App` class, host context, patterns, pitfalls. **Canonical example** (`examples/mcp-apps-canonical/`, `npm run example:mcp-apps`) and widget-side debug helpers (`mcp-debug-log`, `mcp-debug-refresh`). Cross-links to Agent Tester as a dev-host (doc 08) | Building / extending MCP Apps (UI-augmented tools) |
|
|
26
|
+
| [11-public-contract](11-public-contract.md) | Formal public-contract surface of `fa-mcp-sdk`: transports, HTTP endpoints, JWT claims, tool/prompt/resource shape, error mapping, limits & headers (`X-Request-Id`, `traceparent`, `Retry-After`, `WWW-Authenticate`, `MCP-Session-Id`), semver policy, deprecation process | Pinning SDK version, planning a SDK upgrade, drafting CHANGELOG entries, deciding MAJOR vs MINOR vs PATCH |
|
|
26
27
|
|
|
27
28
|
## Key Exports
|
|
28
29
|
|
|
@@ -40,6 +41,28 @@ import {
|
|
|
40
41
|
getJsonFromResult,
|
|
41
42
|
TToolHandlerResponse, IToolHandlerTextResponse, IToolHandlerStructuredResponse,
|
|
42
43
|
ToolExecutionError, ServerError, BaseMcpError, ValidationError, getTools,
|
|
44
|
+
// Appendix B errors — emitted by the SDK transport; re-throwable from tool / API code
|
|
45
|
+
PayloadTooLargeError, TimeoutError, RateLimitedError, ResourceNotFoundError,
|
|
46
|
+
MCP_ERROR_CODES, IMcpErrorData, createJsonRpcErrorResponse,
|
|
47
|
+
} from 'fa-mcp-sdk';
|
|
48
|
+
|
|
49
|
+
// Prompts (parameterised — standard §10.5) & Resources (templates/subscribe — §11.5)
|
|
50
|
+
import {
|
|
51
|
+
IPromptArgument, IPromptData,
|
|
52
|
+
IIcon, // §10.5/§11.3 — optional title/icons UI metadata
|
|
53
|
+
IResourceTemplateInfo,
|
|
54
|
+
notifyResourceUpdated, // call to broadcast `notifications/resources/updated`
|
|
55
|
+
} from 'fa-mcp-sdk';
|
|
56
|
+
|
|
57
|
+
// SSE resumability (standard §6) — opt-in via mcp.sse.resumability; maskSensitive (§12.2) — opt-in
|
|
58
|
+
// result masking, applied by the server inside a tool handler.
|
|
59
|
+
import { InMemoryEventStore, maskSensitive, IMaskRules } from 'fa-mcp-sdk';
|
|
60
|
+
|
|
61
|
+
// Task-augmented execution (standard §8.7) — opt-in via mcp.tasks.enabled; declare a long-running
|
|
62
|
+
// tool with execution.taskSupport. Storage is pluggable (default: in-memory, per-process).
|
|
63
|
+
import {
|
|
64
|
+
getTaskStore, resetTaskStore, InMemoryTaskStore, toTaskDto, isTerminalTaskStatus,
|
|
65
|
+
ITaskStore, ITaskRecord, ITaskCreateInput, ITaskStoreOptions, TTaskStatus, TTaskPatch,
|
|
43
66
|
} from 'fa-mcp-sdk';
|
|
44
67
|
|
|
45
68
|
// Database & Cache
|
|
@@ -9,14 +9,67 @@ import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
|
9
9
|
|
|
10
10
|
export const tools: Tool[] = [{
|
|
11
11
|
name: 'my_custom_tool',
|
|
12
|
+
title: 'My custom tool', // SHOULD §9.1 — human-readable name
|
|
12
13
|
description: 'Description of what this tool does',
|
|
13
14
|
inputSchema: {
|
|
15
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema', // standard §9.2
|
|
14
16
|
type: 'object',
|
|
15
17
|
properties: {
|
|
16
18
|
query: { type: 'string', description: 'Input query' },
|
|
17
19
|
options: { type: 'object', description: 'Optional config' },
|
|
18
20
|
},
|
|
19
21
|
required: ['query'],
|
|
22
|
+
additionalProperties: false, // reject unknown fields
|
|
23
|
+
},
|
|
24
|
+
}];
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Standard §9.1 (MUST) — tool name `name` MUST match `/^[a-z][a-z0-9_]{0,62}$/`** (ASCII
|
|
28
|
+
snake_case, 1..63 chars). The SDK validates names eagerly at `initMcpServer()` for static
|
|
29
|
+
tool arrays and lazily on the first `getTools()` call for dynamic (function-form) tools — a
|
|
30
|
+
violation throws with the offending name printed.
|
|
31
|
+
|
|
32
|
+
**Standard §9.2 — `inputSchema` SHOULD declare `$schema: '…/draft/2020-12/schema'` and
|
|
33
|
+
`additionalProperties: false`.** Both fields are recognised by the `IToolInputSchema` type.
|
|
34
|
+
|
|
35
|
+
**Standard §9.3 (MUST) — arguments are validated server-side.** Before `toolHandler` is
|
|
36
|
+
called, the SDK validates `request.params.arguments` against `inputSchema` via ajv (draft
|
|
37
|
+
2020-12). On failure the response is JSON-RPC `-32602` with
|
|
38
|
+
`error.data = { field, reason }`; the handler is **not** invoked. This means tool code
|
|
39
|
+
no longer needs to repeat shape checks — by the time the handler runs, `args` already
|
|
40
|
+
matches the schema.
|
|
41
|
+
|
|
42
|
+
### Output schema and `structuredContent` (standard §9.4 / §12.4)
|
|
43
|
+
|
|
44
|
+
A tool MAY declare `outputSchema` to describe its `structuredContent` payload. When set,
|
|
45
|
+
the SDK validates the handler's response against the schema — a violation raises JSON-RPC
|
|
46
|
+
`-32603` (internal error: the tool broke its own contract). Whenever a response includes
|
|
47
|
+
`structuredContent`, the SDK mirrors a serialised JSON copy into `content[0].text` so
|
|
48
|
+
legacy clients that only read `content` keep working without code changes.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
export const tools: Tool[] = [{
|
|
52
|
+
name: 'search_docs',
|
|
53
|
+
title: 'Search documents',
|
|
54
|
+
description: 'Vector search over the knowledge base.',
|
|
55
|
+
inputSchema: { /* …as above… */ },
|
|
56
|
+
outputSchema: {
|
|
57
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: {
|
|
60
|
+
results: {
|
|
61
|
+
type: 'array',
|
|
62
|
+
items: {
|
|
63
|
+
type: 'object',
|
|
64
|
+
properties: { id: { type: 'string' }, score: { type: 'number' } },
|
|
65
|
+
required: ['id'],
|
|
66
|
+
additionalProperties: true,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
total: { type: 'number' },
|
|
70
|
+
},
|
|
71
|
+
required: ['results'],
|
|
72
|
+
additionalProperties: true,
|
|
20
73
|
},
|
|
21
74
|
}];
|
|
22
75
|
```
|
|
@@ -135,6 +188,148 @@ const clientIP = headers?.['x-real-ip'] || headers?.['x-forwarded-for'];
|
|
|
135
188
|
`clientCapabilities`). See
|
|
136
189
|
[ITransportContext](./02-2-prompts-and-resources.md#itransportcontext).
|
|
137
190
|
|
|
191
|
+
### Cancellation (`signal`) — standard §8.5
|
|
192
|
+
|
|
193
|
+
`IToolHandlerParams.signal?: AbortSignal` is flipped when the client sends
|
|
194
|
+
`notifications/cancelled` for the current request. Pass it straight to any downstream
|
|
195
|
+
`AbortSignal`-aware API (`fetch`, `pg`, `axios` ≥ 0.22, …) — they will abort their work and
|
|
196
|
+
let the rejection propagate. Tool handlers MUST stop work once the signal aborts; the SDK
|
|
197
|
+
then suppresses the JSON-RPC response per §8.5.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
export const handleToolCall = async (params: IToolHandlerParams): Promise<TToolHandlerResponse> => {
|
|
201
|
+
const { name, arguments: args, signal } = params;
|
|
202
|
+
|
|
203
|
+
switch (name) {
|
|
204
|
+
case 'search_documents': {
|
|
205
|
+
// Native AbortSignal forwarding — fetch will throw AbortError when the client cancels.
|
|
206
|
+
const res = await fetch(`https://docs.example.com/search?q=${encodeURIComponent(args.q)}`, {
|
|
207
|
+
signal,
|
|
208
|
+
});
|
|
209
|
+
const items = await res.json();
|
|
210
|
+
return formatToolResult({ items });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
For libraries that do not understand `AbortSignal` natively, gate the work with
|
|
217
|
+
`signal.aborted` checks at safe seams (between DB pages, loop iterations, retry attempts):
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
case 'long_running': {
|
|
221
|
+
for (const chunk of chunks) {
|
|
222
|
+
if (signal?.aborted) {
|
|
223
|
+
throw signal.reason ?? new Error('cancelled');
|
|
224
|
+
}
|
|
225
|
+
await process(chunk);
|
|
226
|
+
}
|
|
227
|
+
return formatToolResult({ ok: true });
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
When `signal` is `undefined` (legacy transports or older SDK consumers), behave as if it were
|
|
232
|
+
never aborted — handlers should remain forward-compatible.
|
|
233
|
+
|
|
234
|
+
### Progress (`sendProgress`) — standard §8.6
|
|
235
|
+
|
|
236
|
+
`IToolHandlerParams.sendProgress?` emits `notifications/progress` whenever the request
|
|
237
|
+
carried `_meta.progressToken`. When the client did not request progress, the SDK passes a
|
|
238
|
+
no-op so the handler can call it unconditionally — no `if` guard needed.
|
|
239
|
+
|
|
240
|
+
Rules enforced server-side:
|
|
241
|
+
|
|
242
|
+
- progress values MUST be monotonically non-decreasing (smaller values are silently dropped);
|
|
243
|
+
- emissions are throttled by `mcp.progress.throttleMs` (default 100 ms → max 10 events/s).
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
case 'bulk_import': {
|
|
247
|
+
const rows = await loadRows(args.source);
|
|
248
|
+
for (let i = 0; i < rows.length; i++) {
|
|
249
|
+
if (signal?.aborted) {
|
|
250
|
+
throw signal.reason ?? new Error('cancelled');
|
|
251
|
+
}
|
|
252
|
+
await importRow(rows[i]);
|
|
253
|
+
sendProgress?.(i + 1, rows.length, `imported ${rows[i].id}`);
|
|
254
|
+
}
|
|
255
|
+
return formatToolResult({ inserted: rows.length });
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The client receives:
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"method": "notifications/progress",
|
|
264
|
+
"params": {
|
|
265
|
+
"progressToken": "abc-123",
|
|
266
|
+
"progress": 42,
|
|
267
|
+
"total": 100,
|
|
268
|
+
"message": "imported acct-42"
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Choose `total` only when the upper bound is known up-front; otherwise omit it and the client
|
|
274
|
+
will render an indeterminate spinner.
|
|
275
|
+
|
|
276
|
+
### Task-augmented execution (long-running tools) — standard §8.7
|
|
277
|
+
|
|
278
|
+
A normal `tools/call` is synchronous: the client holds the connection open until the tool returns,
|
|
279
|
+
and the call is bound by the tool timeout (`mcp.limits.toolTimeoutMs`, 30 seconds by default). For
|
|
280
|
+
operations that legitimately take minutes — bulk exports, report generation, long searches — the
|
|
281
|
+
SDK supports **task-augmented execution**: the server returns a task identifier immediately and runs
|
|
282
|
+
the tool in the background; the client then polls for status and fetches the result when ready.
|
|
283
|
+
|
|
284
|
+
This feature is **opt-in and off by default**. To enable it:
|
|
285
|
+
|
|
286
|
+
1. Set `mcp.tasks.enabled: true` in the configuration. The server then advertises the `tasks`
|
|
287
|
+
capability and accepts the lifecycle methods `tasks/list`, `tasks/get`, `tasks/result` and
|
|
288
|
+
`tasks/cancel`.
|
|
289
|
+
2. Mark the long-running tool with `execution.taskSupport` in its declaration:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
{
|
|
293
|
+
name: 'generate_report',
|
|
294
|
+
title: 'Generate a large report',
|
|
295
|
+
description: 'Builds a multi-page report. Long-running — call it as a task.',
|
|
296
|
+
inputSchema: { /* … */ },
|
|
297
|
+
// 'optional' — the client MAY ask for a task but can still call synchronously.
|
|
298
|
+
// 'required' — the tool runs only as a task (a synchronous call is rejected with -32602).
|
|
299
|
+
// 'forbidden' / omitted — synchronous only.
|
|
300
|
+
execution: { taskSupport: 'optional' },
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
The same handler runs whether the tool is invoked synchronously or as a task — the SDK always
|
|
305
|
+
supplies `signal` and `sendProgress`. When the tool runs as a task, `signal` is flipped by
|
|
306
|
+
`tasks/cancel`, progress is delivered through `notifications/progress`, and the SDK emits a
|
|
307
|
+
`notifications/tasks/status` on every status change. On completion the task transitions to
|
|
308
|
+
`completed` (carrying the same result a synchronous call would return); on a thrown error it
|
|
309
|
+
transitions to `failed` with a sanitized message; on cancellation it transitions to `cancelled`.
|
|
310
|
+
|
|
311
|
+
The client drives the lifecycle by sending a `task` parameter on `tools/call` and then polling:
|
|
312
|
+
|
|
313
|
+
```jsonc
|
|
314
|
+
// 1. Create — returns immediately with { task: { taskId, status: "working", … } }
|
|
315
|
+
{ "method": "tools/call", "params": { "name": "generate_report", "arguments": {}, "task": {} } }
|
|
316
|
+
|
|
317
|
+
// 2. Poll status until terminal
|
|
318
|
+
{ "method": "tasks/get", "params": { "taskId": "…" } } // → { status: "working" | "completed" | … }
|
|
319
|
+
|
|
320
|
+
// 3. Fetch the result once completed (same shape a synchronous tools/call returns)
|
|
321
|
+
{ "method": "tasks/result", "params": { "taskId": "…" } }
|
|
322
|
+
|
|
323
|
+
// Optional — abort a running task
|
|
324
|
+
{ "method": "tasks/cancel", "params": { "taskId": "…" } }
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The default task store keeps records **in process memory only** — it does not survive a server
|
|
328
|
+
restart, and it is scoped to a single instance (no shared store across a cluster). Retention,
|
|
329
|
+
poll interval and the retained-task cap are configured under `mcp.tasks.*` (see
|
|
330
|
+
[03-configuration.md](./03-configuration.md)); the full method contract is in
|
|
331
|
+
[11-public-contract.md](./11-public-contract.md) §4.
|
|
332
|
+
|
|
138
333
|
### MCP Apps — Reading Client Capabilities
|
|
139
334
|
|
|
140
335
|
`params.clientCapabilities` carries the client's `initialize`-time capabilities (including the
|