@agent-id/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/README.md ADDED
@@ -0,0 +1,121 @@
1
+ # agentID
2
+
3
+ MCP server that gives AI agents a verified identity. It authenticates the user via BankID, gets a signed JWT, and attaches it to every HTTP request the agent makes.
4
+
5
+ Websites can verify the token offline using agentID's public keys — no need to block AI agents when you can verify who's behind them.
6
+
7
+ ## How it works
8
+
9
+ ```
10
+ ┌──────────────────┐
11
+ │ agentID API │
12
+ │ (BankID + JWT) │
13
+ └──────┬───────────┘
14
+ │ 1. authenticate via BankID
15
+ │ 2. receive signed JWT
16
+
17
+ User ← stdio → MCP Server ← HTTP + X-AgentID-Token → any website
18
+
19
+ │ website verifies JWT via /api/jwks
20
+ ```
21
+
22
+ ### Authentication flow
23
+
24
+ 1. Agent calls `start_authentication` → gets a BankID auth URL
25
+ 2. Agent shows the URL to the user → user completes BankID on their phone
26
+ 3. Agent calls `complete_authentication` → MCP server polls until done, caches the JWT
27
+ 4. Agent calls `authenticated_fetch` → every request carries `X-AgentID-Token: <jwt>`
28
+
29
+ The JWT contains a pseudonymous identity (no PII), expires after 1 hour, and is signed with RS256.
30
+
31
+ ## Quick start
32
+
33
+ ```bash
34
+ npm install
35
+ npm run build
36
+ ```
37
+
38
+ ## Claude Desktop config
39
+
40
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
41
+
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "agentID": {
46
+ "command": "node",
47
+ "args": ["/absolute/path/to/agentID/dist/index.js"]
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ Or if published to npm:
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ "agentID": {
59
+ "command": "npx",
60
+ "args": ["agentID"]
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ ## MCP Tools
67
+
68
+ ### `start_authentication`
69
+
70
+ Start a BankID authentication session. Returns an `authUrl` to show the user and a `sessionId` for polling.
71
+
72
+ No parameters.
73
+
74
+ ### `complete_authentication`
75
+
76
+ Poll until BankID authentication completes. Caches the JWT automatically.
77
+
78
+ | Param | Type | Required | Description |
79
+ |-------|------|----------|-------------|
80
+ | `sessionId` | string | yes | Session ID from `start_authentication` |
81
+
82
+ ### `authenticated_fetch`
83
+
84
+ Make an HTTP request with the cached agentID token attached as `X-AgentID-Token`.
85
+
86
+ | Param | Type | Required | Description |
87
+ |-------|------|----------|-------------|
88
+ | `url` | string | yes | URL to fetch |
89
+ | `method` | GET / POST / PUT / DELETE | no (default GET) | HTTP method |
90
+ | `body` | string | no | Request body for POST/PUT |
91
+ | `headers` | object | no | Additional headers |
92
+
93
+ Returns an error if no valid token is cached — call `start_authentication` first.
94
+
95
+ ## Example server
96
+
97
+ A demo Express server that checks for the `X-AgentID-Token` header:
98
+
99
+ ```bash
100
+ # Start it
101
+ npx ts-node example-server/server.ts
102
+
103
+ # Without token → 403
104
+ curl http://localhost:4000/whoami
105
+
106
+ # With token → 200
107
+ curl -H "X-AgentID-Token: any-token" http://localhost:4000/whoami
108
+ ```
109
+
110
+ Endpoints:
111
+ - `GET /whoami` — agent verification status
112
+ - `GET /data` — sample protected data
113
+ - `POST /echo` — echoes request body
114
+
115
+ ## Development
116
+
117
+ ```bash
118
+ npm run dev # watch mode
119
+ npm run build # compile TypeScript
120
+ npm start # run the compiled server
121
+ ```
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const axios_1 = __importDefault(require("axios"));
10
+ const zod_1 = require("zod");
11
+ // --- Config ---
12
+ const AGENTID_URL = "https://agentpass.vercel.app";
13
+ // --- Token cache ---
14
+ let cachedToken = null;
15
+ let tokenExpiresAt = 0;
16
+ function getToken() {
17
+ if (cachedToken && Date.now() < tokenExpiresAt) {
18
+ return cachedToken;
19
+ }
20
+ cachedToken = null;
21
+ return null;
22
+ }
23
+ function setToken(jwt) {
24
+ cachedToken = jwt;
25
+ // Parse exp from JWT payload (base64url-decoded, no verification needed here)
26
+ try {
27
+ const payload = JSON.parse(Buffer.from(jwt.split(".")[1], "base64url").toString());
28
+ // Expire 30s early to avoid edge cases
29
+ tokenExpiresAt = (payload.exp * 1000) - 30_000;
30
+ }
31
+ catch {
32
+ // Fallback: 55 minutes
33
+ tokenExpiresAt = Date.now() + 55 * 60 * 1000;
34
+ }
35
+ }
36
+ // --- Axios client with token interceptor ---
37
+ const client = axios_1.default.create();
38
+ client.interceptors.request.use((config) => {
39
+ const token = getToken();
40
+ if (token) {
41
+ config.headers.set("X-AgentID-Token", token);
42
+ }
43
+ return config;
44
+ });
45
+ // --- Helpers ---
46
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
47
+ function textResult(data, isError = false) {
48
+ return {
49
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
50
+ isError,
51
+ };
52
+ }
53
+ // --- MCP Server ---
54
+ const server = new mcp_js_1.McpServer({
55
+ name: "agentID",
56
+ version: "1.0.0",
57
+ });
58
+ // Tool 1: Start BankID authentication
59
+ server.tool("start_authentication", "Start a BankID authentication session via agentID. " +
60
+ "Returns an authUrl that the user must open to complete BankID on their phone, " +
61
+ "and a sessionId to pass to complete_authentication.", {}, async () => {
62
+ try {
63
+ const res = await axios_1.default.post(`${AGENTID_URL}/api/auth/start`);
64
+ const { sessionId, authUrl, expiresAt } = res.data;
65
+ return textResult({
66
+ message: "BankID authentication started. Show the authUrl to the user so they can authenticate.",
67
+ sessionId,
68
+ authUrl,
69
+ expiresAt,
70
+ });
71
+ }
72
+ catch (error) {
73
+ return textResult({ error: error.response?.data ?? error.message }, true);
74
+ }
75
+ });
76
+ // Tool 2: Poll until BankID authentication completes
77
+ server.tool("complete_authentication", "Poll agentID for BankID authentication completion. " +
78
+ "Call this after the user has been shown the authUrl from start_authentication. " +
79
+ "It will poll every 3 seconds until the user completes BankID, then cache the JWT.", {
80
+ sessionId: zod_1.z
81
+ .string()
82
+ .describe("The sessionId returned by start_authentication"),
83
+ }, async ({ sessionId }) => {
84
+ const maxAttempts = 40; // ~2 minutes
85
+ let attempts = 0;
86
+ while (attempts < maxAttempts) {
87
+ attempts++;
88
+ try {
89
+ const res = await axios_1.default.get(`${AGENTID_URL}/api/auth/status`, {
90
+ params: { sessionId },
91
+ });
92
+ if (res.data.status === "complete") {
93
+ setToken(res.data.jwt);
94
+ return textResult({
95
+ status: "authenticated",
96
+ message: "BankID authentication successful. The agent identity token is now cached " +
97
+ "and will be automatically attached to all authenticated_fetch requests.",
98
+ });
99
+ }
100
+ if (res.data.status === "failed") {
101
+ return textResult({
102
+ status: "failed",
103
+ message: "BankID authentication failed.",
104
+ hintCode: res.data.hintCode,
105
+ }, true);
106
+ }
107
+ // Still pending — wait and retry
108
+ await sleep(3000);
109
+ }
110
+ catch (error) {
111
+ return textResult({ error: error.response?.data ?? error.message }, true);
112
+ }
113
+ }
114
+ return textResult({ status: "timeout", message: "Authentication timed out after 2 minutes." }, true);
115
+ });
116
+ // Tool 3: Make authenticated HTTP requests
117
+ server.tool("authenticated_fetch", "Make an HTTP request with the agent's agentID identity token automatically attached " +
118
+ "as 'X-AgentID-Token'. The user must complete authentication first via " +
119
+ "start_authentication and complete_authentication.", {
120
+ url: zod_1.z.string().url().describe("The URL to fetch"),
121
+ method: zod_1.z
122
+ .enum(["GET", "POST", "PUT", "DELETE"])
123
+ .default("GET")
124
+ .describe("HTTP method"),
125
+ body: zod_1.z
126
+ .string()
127
+ .optional()
128
+ .describe("Request body (for POST/PUT)"),
129
+ headers: zod_1.z
130
+ .record(zod_1.z.string(), zod_1.z.string())
131
+ .optional()
132
+ .describe("Additional headers to include"),
133
+ }, async ({ url, method, body, headers }) => {
134
+ if (!getToken()) {
135
+ return textResult({
136
+ error: "Not authenticated",
137
+ message: "No valid agentID token. Call start_authentication first, " +
138
+ "then complete_authentication after the user finishes BankID.",
139
+ }, true);
140
+ }
141
+ try {
142
+ const response = await client.request({
143
+ url,
144
+ method,
145
+ data: body,
146
+ headers: (headers ?? {}),
147
+ });
148
+ return textResult({
149
+ status: response.status,
150
+ headers: response.headers,
151
+ data: response.data,
152
+ });
153
+ }
154
+ catch (error) {
155
+ return textResult({
156
+ status: error.response?.status ?? "unknown",
157
+ error: error.response?.data ?? error.message,
158
+ }, true);
159
+ }
160
+ });
161
+ // --- Start ---
162
+ async function main() {
163
+ const transport = new stdio_js_1.StdioServerTransport();
164
+ await server.connect(transport);
165
+ console.error("agentID MCP server running on stdio");
166
+ }
167
+ main().catch((err) => {
168
+ console.error("Fatal:", err);
169
+ process.exit(1);
170
+ });
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@agent-id/mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server that gives AI agents a verified identity via BankID",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "agent-id-mcp": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "start": "node dist/index.js",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "mcp",
20
+ "agent",
21
+ "identity",
22
+ "jwt",
23
+ "authentication",
24
+ "bankid"
25
+ ],
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.26.0",
29
+ "axios": "^1.13.5",
30
+ "zod": "^4.3.6"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^25.3.0",
34
+ "typescript": "^5.9.3"
35
+ }
36
+ }