toolcraft 0.0.5 → 0.0.7

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.
Files changed (149) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.d.ts +1 -0
  3. package/dist/cli.js +77 -59
  4. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.d.ts +2 -0
  5. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.js +15 -0
  6. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.d.ts +2 -0
  7. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.js +13 -0
  8. package/node_modules/@poe-code/agent-defs/dist/agents/codex.d.ts +2 -0
  9. package/node_modules/@poe-code/agent-defs/dist/agents/codex.js +14 -0
  10. package/node_modules/@poe-code/agent-defs/dist/agents/goose.d.ts +2 -0
  11. package/node_modules/@poe-code/agent-defs/dist/agents/goose.js +14 -0
  12. package/node_modules/@poe-code/agent-defs/dist/agents/index.d.ts +7 -0
  13. package/node_modules/@poe-code/agent-defs/dist/agents/index.js +7 -0
  14. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.d.ts +2 -0
  15. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.js +15 -0
  16. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.d.ts +2 -0
  17. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.js +14 -0
  18. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.d.ts +2 -0
  19. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.js +13 -0
  20. package/node_modules/@poe-code/agent-defs/dist/index.d.ts +5 -0
  21. package/node_modules/@poe-code/agent-defs/dist/index.js +3 -0
  22. package/node_modules/@poe-code/agent-defs/dist/registry.d.ts +3 -0
  23. package/node_modules/@poe-code/agent-defs/dist/registry.js +26 -0
  24. package/node_modules/@poe-code/agent-defs/dist/specifier.d.ts +7 -0
  25. package/node_modules/@poe-code/agent-defs/dist/specifier.js +27 -0
  26. package/node_modules/@poe-code/agent-defs/dist/types.d.ts +16 -0
  27. package/node_modules/@poe-code/agent-defs/dist/types.js +1 -0
  28. package/node_modules/@poe-code/agent-defs/package.json +20 -0
  29. package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.d.ts +5 -0
  30. package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.js +552 -0
  31. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.d.ts +17 -0
  32. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.js +58 -0
  33. package/node_modules/@poe-code/config-mutations/dist/execution/run-mutations.d.ts +7 -0
  34. package/node_modules/@poe-code/config-mutations/dist/execution/run-mutations.js +46 -0
  35. package/node_modules/@poe-code/config-mutations/dist/formats/index.d.ts +13 -0
  36. package/node_modules/@poe-code/config-mutations/dist/formats/index.js +49 -0
  37. package/node_modules/@poe-code/config-mutations/dist/formats/json.d.ts +31 -0
  38. package/node_modules/@poe-code/config-mutations/dist/formats/json.js +140 -0
  39. package/node_modules/@poe-code/config-mutations/dist/formats/toml.d.ts +2 -0
  40. package/node_modules/@poe-code/config-mutations/dist/formats/toml.js +72 -0
  41. package/node_modules/@poe-code/config-mutations/dist/formats/yaml.d.ts +2 -0
  42. package/node_modules/@poe-code/config-mutations/dist/formats/yaml.js +73 -0
  43. package/node_modules/@poe-code/config-mutations/dist/fs-utils.d.ts +18 -0
  44. package/node_modules/@poe-code/config-mutations/dist/fs-utils.js +45 -0
  45. package/node_modules/@poe-code/config-mutations/dist/index.d.ts +8 -0
  46. package/node_modules/@poe-code/config-mutations/dist/index.js +8 -0
  47. package/node_modules/@poe-code/config-mutations/dist/mutations/config-mutation.d.ts +47 -0
  48. package/node_modules/@poe-code/config-mutations/dist/mutations/config-mutation.js +34 -0
  49. package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.d.ts +52 -0
  50. package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.js +46 -0
  51. package/node_modules/@poe-code/config-mutations/dist/mutations/template-mutation.d.ts +40 -0
  52. package/node_modules/@poe-code/config-mutations/dist/mutations/template-mutation.js +32 -0
  53. package/node_modules/@poe-code/config-mutations/dist/template/render.d.ts +7 -0
  54. package/node_modules/@poe-code/config-mutations/dist/template/render.js +28 -0
  55. package/node_modules/@poe-code/config-mutations/dist/testing/format-utils.d.ts +7 -0
  56. package/node_modules/@poe-code/config-mutations/dist/testing/format-utils.js +21 -0
  57. package/node_modules/@poe-code/config-mutations/dist/testing/index.d.ts +3 -0
  58. package/node_modules/@poe-code/config-mutations/dist/testing/index.js +2 -0
  59. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.d.ts +25 -0
  60. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.js +170 -0
  61. package/node_modules/@poe-code/config-mutations/dist/types.d.ts +156 -0
  62. package/node_modules/@poe-code/config-mutations/dist/types.js +6 -0
  63. package/node_modules/@poe-code/config-mutations/package.json +33 -0
  64. package/node_modules/@poe-code/file-lock/README.md +52 -0
  65. package/node_modules/@poe-code/file-lock/dist/index.d.ts +1 -0
  66. package/node_modules/@poe-code/file-lock/dist/index.js +1 -0
  67. package/node_modules/@poe-code/file-lock/dist/lock.d.ts +27 -0
  68. package/node_modules/@poe-code/file-lock/dist/lock.js +203 -0
  69. package/node_modules/@poe-code/file-lock/package.json +23 -0
  70. package/node_modules/auth-store/README.md +47 -0
  71. package/node_modules/auth-store/dist/create-secret-store.d.ts +2 -0
  72. package/node_modules/auth-store/dist/create-secret-store.js +35 -0
  73. package/node_modules/auth-store/dist/encrypted-file-store.d.ts +39 -0
  74. package/node_modules/auth-store/dist/encrypted-file-store.js +156 -0
  75. package/node_modules/auth-store/dist/index.d.ts +7 -0
  76. package/node_modules/auth-store/dist/index.js +4 -0
  77. package/node_modules/auth-store/dist/keychain-store.d.ts +22 -0
  78. package/node_modules/auth-store/dist/keychain-store.js +111 -0
  79. package/node_modules/auth-store/dist/provider-store.d.ts +10 -0
  80. package/node_modules/auth-store/dist/provider-store.js +28 -0
  81. package/node_modules/auth-store/dist/types.d.ts +20 -0
  82. package/node_modules/auth-store/dist/types.js +1 -0
  83. package/node_modules/auth-store/package.json +25 -0
  84. package/node_modules/mcp-oauth/README.md +31 -0
  85. package/node_modules/mcp-oauth/dist/client/auth-store-session-store.d.ts +14 -0
  86. package/node_modules/mcp-oauth/dist/client/auth-store-session-store.js +97 -0
  87. package/node_modules/mcp-oauth/dist/client/authorization-state.d.ts +8 -0
  88. package/node_modules/mcp-oauth/dist/client/authorization-state.js +34 -0
  89. package/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.d.ts +3 -0
  90. package/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +491 -0
  91. package/node_modules/mcp-oauth/dist/client/loopback-authorization.d.ts +20 -0
  92. package/node_modules/mcp-oauth/dist/client/loopback-authorization.js +169 -0
  93. package/node_modules/mcp-oauth/dist/client/pkce.d.ts +2 -0
  94. package/node_modules/mcp-oauth/dist/client/pkce.js +7 -0
  95. package/node_modules/mcp-oauth/dist/client/token-endpoint.d.ts +40 -0
  96. package/node_modules/mcp-oauth/dist/client/token-endpoint.js +143 -0
  97. package/node_modules/mcp-oauth/dist/client/types.d.ts +113 -0
  98. package/node_modules/mcp-oauth/dist/client/types.js +1 -0
  99. package/node_modules/mcp-oauth/dist/index.d.ts +10 -0
  100. package/node_modules/mcp-oauth/dist/index.js +7 -0
  101. package/node_modules/mcp-oauth/dist/resource-indicator.d.ts +1 -0
  102. package/node_modules/mcp-oauth/dist/resource-indicator.js +11 -0
  103. package/node_modules/mcp-oauth/dist/server/jwks-token-verifier.d.ts +27 -0
  104. package/node_modules/mcp-oauth/dist/server/jwks-token-verifier.js +259 -0
  105. package/node_modules/mcp-oauth/dist/types.compile-check.d.ts +1 -0
  106. package/node_modules/mcp-oauth/dist/types.compile-check.js +22 -0
  107. package/node_modules/mcp-oauth/package.json +31 -0
  108. package/node_modules/tiny-mcp-client/.turbo/turbo-build.log +4 -0
  109. package/node_modules/tiny-mcp-client/dist/index.d.ts +2 -0
  110. package/node_modules/tiny-mcp-client/dist/index.js +1 -0
  111. package/node_modules/tiny-mcp-client/dist/internal.d.ts +547 -0
  112. package/node_modules/tiny-mcp-client/dist/internal.js +2404 -0
  113. package/node_modules/tiny-mcp-client/dist/jsonrpc-types.compile-check.d.ts +1 -0
  114. package/node_modules/tiny-mcp-client/dist/jsonrpc-types.compile-check.js +37 -0
  115. package/node_modules/tiny-mcp-client/dist/mcp-lifecycle-types.compile-check.d.ts +1 -0
  116. package/node_modules/tiny-mcp-client/dist/mcp-lifecycle-types.compile-check.js +50 -0
  117. package/node_modules/tiny-mcp-client/dist/mcp-prompt-types.compile-check.d.ts +1 -0
  118. package/node_modules/tiny-mcp-client/dist/mcp-prompt-types.compile-check.js +50 -0
  119. package/node_modules/tiny-mcp-client/dist/mcp-resource-types.compile-check.d.ts +1 -0
  120. package/node_modules/tiny-mcp-client/dist/mcp-resource-types.compile-check.js +51 -0
  121. package/node_modules/tiny-mcp-client/dist/mcp-tool-types.compile-check.d.ts +1 -0
  122. package/node_modules/tiny-mcp-client/dist/mcp-tool-types.compile-check.js +89 -0
  123. package/node_modules/tiny-mcp-client/dist/mcp-transport-types.compile-check.d.ts +1 -0
  124. package/node_modules/tiny-mcp-client/dist/mcp-transport-types.compile-check.js +56 -0
  125. package/node_modules/tiny-mcp-client/dist/mcp-utility-types.compile-check.d.ts +1 -0
  126. package/node_modules/tiny-mcp-client/dist/mcp-utility-types.compile-check.js +145 -0
  127. package/node_modules/tiny-mcp-client/dist/oauth-discovery.d.ts +24 -0
  128. package/node_modules/tiny-mcp-client/dist/oauth-discovery.js +385 -0
  129. package/node_modules/tiny-mcp-client/package.json +22 -0
  130. package/node_modules/tiny-mcp-client/src/http-oauth.integration.test.ts +823 -0
  131. package/node_modules/tiny-mcp-client/src/http-oauth.test.ts +882 -0
  132. package/node_modules/tiny-mcp-client/src/index.ts +94 -0
  133. package/node_modules/tiny-mcp-client/src/internal.ts +3566 -0
  134. package/node_modules/tiny-mcp-client/src/jsonrpc-types.compile-check.ts +66 -0
  135. package/node_modules/tiny-mcp-client/src/mcp-client-http-transport.integration.test.ts +222 -0
  136. package/node_modules/tiny-mcp-client/src/mcp-client-sdk.test.ts +1294 -0
  137. package/node_modules/tiny-mcp-client/src/mcp-client-tiny-stdio-test-server-tools.test.ts +143 -0
  138. package/node_modules/tiny-mcp-client/src/mcp-lifecycle-types.compile-check.ts +65 -0
  139. package/node_modules/tiny-mcp-client/src/mcp-prompt-types.compile-check.ts +66 -0
  140. package/node_modules/tiny-mcp-client/src/mcp-resource-types.compile-check.ts +70 -0
  141. package/node_modules/tiny-mcp-client/src/mcp-tool-types.compile-check.ts +117 -0
  142. package/node_modules/tiny-mcp-client/src/mcp-transport-types.compile-check.ts +75 -0
  143. package/node_modules/tiny-mcp-client/src/mcp-utility-types.compile-check.ts +181 -0
  144. package/node_modules/tiny-mcp-client/src/mock-servers.test.ts +980 -0
  145. package/node_modules/tiny-mcp-client/src/oauth-discovery.ts +583 -0
  146. package/node_modules/tiny-mcp-client/src/transports.test.ts +8139 -0
  147. package/node_modules/tiny-mcp-client/src/utilities.test.ts +372 -0
  148. package/node_modules/tiny-mcp-client/tsconfig.json +11 -0
  149. package/package.json +24 -11
@@ -0,0 +1,40 @@
1
+ import type { OAuthMetadataFetch, StoredOAuthTokens } from "./types.js";
2
+ interface OAuthErrorShape {
3
+ error: string;
4
+ error_description?: string;
5
+ error_uri?: string;
6
+ }
7
+ export declare class OAuthError extends Error {
8
+ readonly error: string;
9
+ readonly errorDescription: string | undefined;
10
+ readonly errorUri: string | undefined;
11
+ readonly error_description: string | undefined;
12
+ readonly error_uri: string | undefined;
13
+ readonly status: number;
14
+ readonly retryable: boolean;
15
+ readonly terminal: boolean;
16
+ constructor(shape: OAuthErrorShape, status: number);
17
+ }
18
+ export declare function isRetryableOAuthError(error: unknown): error is OAuthError;
19
+ export declare function exchangeAuthorizationCode(input: {
20
+ tokenEndpoint: string;
21
+ clientId: string;
22
+ clientSecret?: string;
23
+ code: string;
24
+ codeVerifier: string;
25
+ redirectUri: string;
26
+ resource: string;
27
+ fetch: OAuthMetadataFetch;
28
+ now: () => number;
29
+ }): Promise<StoredOAuthTokens>;
30
+ export declare function refreshAccessToken(input: {
31
+ tokenEndpoint: string;
32
+ clientId: string;
33
+ clientSecret?: string;
34
+ refreshToken: string;
35
+ resource: string;
36
+ fetch: OAuthMetadataFetch;
37
+ now: () => number;
38
+ }): Promise<StoredOAuthTokens>;
39
+ export declare function readOAuthJsonObjectResponse(response: Response): Promise<Record<string, unknown>>;
40
+ export {};
@@ -0,0 +1,143 @@
1
+ import { canonicalizeResourceIndicator } from "../resource-indicator.js";
2
+ export class OAuthError extends Error {
3
+ error;
4
+ errorDescription;
5
+ errorUri;
6
+ error_description;
7
+ error_uri;
8
+ status;
9
+ retryable;
10
+ terminal;
11
+ constructor(shape, status) {
12
+ super(shape.error_description ?? shape.error);
13
+ this.name = "OAuthError";
14
+ this.error = shape.error;
15
+ this.errorDescription = shape.error_description;
16
+ this.errorUri = shape.error_uri;
17
+ this.error_description = shape.error_description;
18
+ this.error_uri = shape.error_uri;
19
+ this.status = status;
20
+ this.retryable = isRetryableOAuthError(this);
21
+ this.terminal = !this.retryable;
22
+ }
23
+ }
24
+ export function isRetryableOAuthError(error) {
25
+ return (error instanceof OAuthError
26
+ && (error.status >= 500
27
+ || error.error === "server_error"
28
+ || error.error === "temporarily_unavailable"));
29
+ }
30
+ export async function exchangeAuthorizationCode(input) {
31
+ const resource = canonicalizeResourceIndicator(input.resource);
32
+ return requestTokens({
33
+ tokenEndpoint: input.tokenEndpoint,
34
+ clientId: input.clientId,
35
+ clientSecret: input.clientSecret,
36
+ params: {
37
+ grant_type: "authorization_code",
38
+ code: input.code,
39
+ code_verifier: input.codeVerifier,
40
+ redirect_uri: input.redirectUri,
41
+ resource,
42
+ },
43
+ fetch: input.fetch,
44
+ now: input.now,
45
+ });
46
+ }
47
+ export async function refreshAccessToken(input) {
48
+ const resource = canonicalizeResourceIndicator(input.resource);
49
+ return requestTokens({
50
+ tokenEndpoint: input.tokenEndpoint,
51
+ clientId: input.clientId,
52
+ clientSecret: input.clientSecret,
53
+ params: {
54
+ grant_type: "refresh_token",
55
+ refresh_token: input.refreshToken,
56
+ resource,
57
+ },
58
+ fetch: input.fetch,
59
+ now: input.now,
60
+ });
61
+ }
62
+ async function requestTokens(input) {
63
+ const body = new URLSearchParams({
64
+ client_id: input.clientId,
65
+ ...input.params,
66
+ });
67
+ if (input.clientSecret !== undefined) {
68
+ body.set("client_secret", input.clientSecret);
69
+ }
70
+ const response = await input.fetch(input.tokenEndpoint, {
71
+ method: "POST",
72
+ headers: {
73
+ "Content-Type": "application/x-www-form-urlencoded",
74
+ },
75
+ body: body.toString(),
76
+ });
77
+ const payload = await readOAuthJsonObjectResponse(response);
78
+ if (typeof payload.access_token !== "string" || payload.access_token.length === 0) {
79
+ throw new Error("OAuth token response missing access_token");
80
+ }
81
+ const tokenType = normalizeBearerTokenType(payload.token_type);
82
+ if (tokenType === null) {
83
+ throw new Error("OAuth token response missing token_type=Bearer");
84
+ }
85
+ return {
86
+ accessToken: payload.access_token,
87
+ refreshToken: typeof payload.refresh_token === "string" && payload.refresh_token.length > 0
88
+ ? payload.refresh_token
89
+ : undefined,
90
+ tokenType,
91
+ expiresAt: typeof payload.expires_in === "number" && Number.isFinite(payload.expires_in)
92
+ ? input.now() + (payload.expires_in * 1000)
93
+ : null,
94
+ scope: typeof payload.scope === "string" && payload.scope.length > 0
95
+ ? payload.scope
96
+ : undefined,
97
+ };
98
+ }
99
+ export async function readOAuthJsonObjectResponse(response) {
100
+ const fallbackError = createFallbackOAuthError(response.status);
101
+ let payload;
102
+ try {
103
+ payload = await response.json();
104
+ }
105
+ catch {
106
+ if (!response.ok) {
107
+ throw fallbackError;
108
+ }
109
+ throw new Error("OAuth response must be a JSON object");
110
+ }
111
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
112
+ if (!response.ok) {
113
+ throw fallbackError;
114
+ }
115
+ throw new Error("OAuth response must be a JSON object");
116
+ }
117
+ const record = payload;
118
+ if (!response.ok) {
119
+ throw new OAuthError(readOAuthError(record, fallbackError.error), response.status);
120
+ }
121
+ return record;
122
+ }
123
+ function readOAuthError(payload, fallbackError = "server_error") {
124
+ return {
125
+ error: typeof payload.error === "string" ? payload.error : fallbackError,
126
+ error_description: typeof payload.error_description === "string"
127
+ ? payload.error_description
128
+ : undefined,
129
+ error_uri: typeof payload.error_uri === "string"
130
+ ? payload.error_uri
131
+ : undefined,
132
+ };
133
+ }
134
+ function createFallbackOAuthError(status) {
135
+ const error = status === 503 ? "temporarily_unavailable" : "server_error";
136
+ return new OAuthError({ error }, status);
137
+ }
138
+ function normalizeBearerTokenType(value) {
139
+ if (typeof value !== "string") {
140
+ return null;
141
+ }
142
+ return value.toLowerCase() === "bearer" ? "Bearer" : null;
143
+ }
@@ -0,0 +1,113 @@
1
+ import type http from "node:http";
2
+ import type { CreateSecretStoreInput } from "auth-store";
3
+ export type OAuthMetadataFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
4
+ export interface OAuthProtectedResourceMetadata extends Record<string, unknown> {
5
+ resource: string;
6
+ authorization_servers: string[];
7
+ }
8
+ export interface OAuthAuthorizationServerMetadata extends Record<string, unknown> {
9
+ issuer: string;
10
+ authorization_endpoint: string;
11
+ token_endpoint: string;
12
+ registration_endpoint?: string;
13
+ response_types_supported: string[];
14
+ code_challenge_methods_supported: string[];
15
+ authorization_response_iss_parameter_supported?: boolean;
16
+ }
17
+ export interface OAuthDiscoveryResult {
18
+ resource: string;
19
+ resourceMetadataUrl: string;
20
+ resourceMetadata: OAuthProtectedResourceMetadata;
21
+ authorizationServer: string;
22
+ authorizationServerMetadataUrl: string;
23
+ authorizationServerMetadata: OAuthAuthorizationServerMetadata;
24
+ }
25
+ export interface OAuthUnauthorizedChallenge {
26
+ scheme: "Bearer";
27
+ params: Record<string, string>;
28
+ raw: string;
29
+ }
30
+ export interface OAuthClientProvider {
31
+ authorizeRequest?(input: {
32
+ requestUrl: URL;
33
+ headers: Headers;
34
+ fetch: OAuthMetadataFetch;
35
+ }): Promise<void> | void;
36
+ handleUnauthorized(input: {
37
+ requestUrl: URL;
38
+ response: Response;
39
+ challenge: OAuthUnauthorizedChallenge | null;
40
+ discovery: OAuthDiscoveryResult;
41
+ fetch: OAuthMetadataFetch;
42
+ }): Promise<{
43
+ action: "retry";
44
+ } | {
45
+ action: "fail";
46
+ error?: Error;
47
+ }> | {
48
+ action: "retry";
49
+ } | {
50
+ action: "fail";
51
+ error?: Error;
52
+ };
53
+ }
54
+ export interface OAuthClientMetadata {
55
+ clientName?: string;
56
+ scope?: string;
57
+ softwareId?: string;
58
+ softwareVersion?: string;
59
+ }
60
+ export interface StoredOAuthTokens {
61
+ accessToken: string;
62
+ refreshToken?: string;
63
+ tokenType: "Bearer";
64
+ expiresAt: number | null;
65
+ scope?: string;
66
+ }
67
+ export interface StoredOAuthSession {
68
+ resource: string;
69
+ authorizationServer: string;
70
+ client: {
71
+ clientId: string;
72
+ clientSecret?: string;
73
+ };
74
+ tokens?: StoredOAuthTokens;
75
+ discovery: {
76
+ resourceMetadataUrl: string;
77
+ resourceMetadata: Record<string, unknown>;
78
+ authorizationServerMetadata: Record<string, unknown>;
79
+ };
80
+ }
81
+ export interface OAuthSessionStore {
82
+ load(resource: string): Promise<StoredOAuthSession | null>;
83
+ save(resource: string, session: StoredOAuthSession): Promise<void>;
84
+ clear(resource: string): Promise<void>;
85
+ }
86
+ export interface DefaultOAuthClientProviderOptions {
87
+ client: {
88
+ mode: "dynamic";
89
+ clientId?: string;
90
+ clientSecret?: string;
91
+ metadata?: OAuthClientMetadata;
92
+ } | {
93
+ mode: "static";
94
+ clientId: string;
95
+ clientSecret?: string;
96
+ metadata?: OAuthClientMetadata;
97
+ };
98
+ browser: {
99
+ openBrowser(url: string): Promise<void>;
100
+ readLine?: () => Promise<string>;
101
+ createServer?: () => http.Server;
102
+ landingPage?: {
103
+ title: string;
104
+ body: string;
105
+ };
106
+ };
107
+ sessionStore?: OAuthSessionStore;
108
+ authStore?: CreateSecretStoreInput;
109
+ now?: () => number;
110
+ }
111
+ export type OAuthClientProviderOptions = {
112
+ provider: OAuthClientProvider;
113
+ } | DefaultOAuthClientProviderOptions;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ export { createAuthStoreSessionStore, } from "./client/auth-store-session-store.js";
2
+ export { createDefaultOAuthClientProvider, createOAuthClientProvider, } from "./client/default-oauth-client-provider.js";
3
+ export { buildSuccessPage, createLoopbackAuthorizationSession, extractCodeFromInput, } from "./client/loopback-authorization.js";
4
+ export { generateCodeChallenge, generateCodeVerifier, } from "./client/pkce.js";
5
+ export { OAuthError, } from "./client/token-endpoint.js";
6
+ export { canonicalizeResourceIndicator, } from "./resource-indicator.js";
7
+ export { createJwksTokenVerifier, } from "./server/jwks-token-verifier.js";
8
+ export type { DefaultOAuthClientProviderOptions, OAuthAuthorizationServerMetadata, OAuthClientMetadata, OAuthClientProvider, OAuthClientProviderOptions, OAuthDiscoveryResult, OAuthMetadataFetch, OAuthProtectedResourceMetadata, OAuthSessionStore, OAuthUnauthorizedChallenge, StoredOAuthSession, StoredOAuthTokens, } from "./client/types.js";
9
+ export type { JwksTokenVerifier, JwksTokenVerifierOptions, JwksVerifiedAccessToken, } from "./server/jwks-token-verifier.js";
10
+ export type { LoopbackAuthorizationOptions, LoopbackAuthorizationSession, OAuthLandingPage, } from "./client/loopback-authorization.js";
@@ -0,0 +1,7 @@
1
+ export { createAuthStoreSessionStore, } from "./client/auth-store-session-store.js";
2
+ export { createDefaultOAuthClientProvider, createOAuthClientProvider, } from "./client/default-oauth-client-provider.js";
3
+ export { buildSuccessPage, createLoopbackAuthorizationSession, extractCodeFromInput, } from "./client/loopback-authorization.js";
4
+ export { generateCodeChallenge, generateCodeVerifier, } from "./client/pkce.js";
5
+ export { OAuthError, } from "./client/token-endpoint.js";
6
+ export { canonicalizeResourceIndicator, } from "./resource-indicator.js";
7
+ export { createJwksTokenVerifier, } from "./server/jwks-token-verifier.js";
@@ -0,0 +1 @@
1
+ export declare function canonicalizeResourceIndicator(value: string | URL): string;
@@ -0,0 +1,11 @@
1
+ export function canonicalizeResourceIndicator(value) {
2
+ let url;
3
+ try {
4
+ url = value instanceof URL ? new URL(value.toString()) : new URL(value);
5
+ }
6
+ catch {
7
+ throw new Error("Resource indicator must be an absolute URL");
8
+ }
9
+ url.hash = "";
10
+ return url.toString();
11
+ }
@@ -0,0 +1,27 @@
1
+ type FetchLike = typeof fetch;
2
+ export interface JwksTokenVerifierOptions {
3
+ jwksUrl: string | URL;
4
+ clockSkewSeconds?: number;
5
+ allowedAlgorithms?: readonly string[];
6
+ fetch?: FetchLike;
7
+ }
8
+ export interface JwksVerifiedAccessToken {
9
+ token: string;
10
+ issuer: string;
11
+ audience: string[];
12
+ scopes: string[];
13
+ expiresAt: number;
14
+ claims: Record<string, unknown>;
15
+ subject?: string;
16
+ clientId?: string;
17
+ }
18
+ export interface JwksTokenVerifier {
19
+ verify(input: {
20
+ token: string;
21
+ resource: string;
22
+ authorizationServers: readonly string[];
23
+ requiredScopes: readonly string[];
24
+ }): Promise<JwksVerifiedAccessToken>;
25
+ }
26
+ export declare function createJwksTokenVerifier(options: JwksTokenVerifierOptions): JwksTokenVerifier;
27
+ export {};
@@ -0,0 +1,259 @@
1
+ import { decodeProtectedHeader, errors, importJWK, jwtVerify, } from "jose";
2
+ import { canonicalizeResourceIndicator } from "../resource-indicator.js";
3
+ const DEFAULT_ALLOWED_ALGORITHMS = [
4
+ "ES256",
5
+ "ES384",
6
+ "ES512",
7
+ "RS256",
8
+ "RS384",
9
+ "RS512",
10
+ "PS256",
11
+ "PS384",
12
+ "PS512",
13
+ "EdDSA",
14
+ ];
15
+ function isTokenVerificationErrorShape(error) {
16
+ if (!(error instanceof Error)) {
17
+ return false;
18
+ }
19
+ const challengeError = error;
20
+ return challengeError.error === "invalid_token"
21
+ || challengeError.error === "insufficient_scope";
22
+ }
23
+ function isObjectRecord(value) {
24
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25
+ }
26
+ function isStringArray(value) {
27
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
28
+ }
29
+ function toUrl(value, label) {
30
+ try {
31
+ return new URL(String(value));
32
+ }
33
+ catch {
34
+ throw new Error(`${label} must be an absolute URL`);
35
+ }
36
+ }
37
+ function normalizeAudience(value) {
38
+ if (typeof value === "string") {
39
+ return [value];
40
+ }
41
+ return isStringArray(value) ? [...value] : [];
42
+ }
43
+ function normalizeVerifiedAudience(value, expectedResource) {
44
+ const audiences = normalizeAudience(value);
45
+ if (audiences.length !== 1) {
46
+ throw createInvalidTokenError("audience mismatch");
47
+ }
48
+ let normalizedAudience;
49
+ try {
50
+ normalizedAudience = canonicalizeResourceIndicator(audiences[0] ?? "");
51
+ }
52
+ catch {
53
+ throw createInvalidTokenError("audience mismatch");
54
+ }
55
+ if (normalizedAudience !== expectedResource) {
56
+ throw createInvalidTokenError("audience mismatch");
57
+ }
58
+ return [normalizedAudience];
59
+ }
60
+ function parseScopes(payload) {
61
+ const raw = typeof payload.scope === "string"
62
+ ? payload.scope
63
+ : typeof payload.scopes === "string"
64
+ ? payload.scopes
65
+ : null;
66
+ if (raw !== null) {
67
+ return raw
68
+ .split(" ")
69
+ .map((scope) => scope.trim())
70
+ .filter((scope) => scope.length > 0);
71
+ }
72
+ return isStringArray(payload.scopes) ? [...payload.scopes] : [];
73
+ }
74
+ function toVerifiedAccessToken(token, payload, audience = normalizeAudience(payload.aud)) {
75
+ return {
76
+ token,
77
+ issuer: typeof payload.iss === "string" ? payload.iss : "",
78
+ audience,
79
+ scopes: parseScopes(payload),
80
+ expiresAt: typeof payload.exp === "number" ? payload.exp : 0,
81
+ claims: { ...payload },
82
+ ...(typeof payload.sub === "string"
83
+ ? {
84
+ subject: payload.sub,
85
+ }
86
+ : {}),
87
+ ...(typeof payload.client_id === "string"
88
+ ? {
89
+ clientId: payload.client_id,
90
+ }
91
+ : {}),
92
+ };
93
+ }
94
+ function createTokenVerificationError(input) {
95
+ return Object.assign(new Error(input.errorDescription ?? input.error), input);
96
+ }
97
+ function createInvalidTokenError(errorDescription) {
98
+ return createTokenVerificationError({
99
+ error: "invalid_token",
100
+ errorDescription,
101
+ });
102
+ }
103
+ function normalizeVerificationError(error) {
104
+ if (isTokenVerificationErrorShape(error)) {
105
+ return error;
106
+ }
107
+ if (error instanceof errors.JWTExpired) {
108
+ return createInvalidTokenError("token expired");
109
+ }
110
+ if (error instanceof errors.JWTClaimValidationFailed) {
111
+ if (error.claim === "aud") {
112
+ return createInvalidTokenError("audience mismatch");
113
+ }
114
+ if (error.claim === "iss") {
115
+ return createInvalidTokenError("issuer mismatch");
116
+ }
117
+ if (error.claim === "nbf") {
118
+ return createInvalidTokenError("token not active yet");
119
+ }
120
+ if (error.claim === "exp") {
121
+ return createInvalidTokenError("token expired");
122
+ }
123
+ }
124
+ if (error instanceof errors.JOSEAlgNotAllowed
125
+ || error instanceof errors.JOSENotSupported) {
126
+ return createInvalidTokenError("unsupported token algorithm");
127
+ }
128
+ if (error instanceof errors.JWKSNoMatchingKey
129
+ || error instanceof errors.JWKSMultipleMatchingKeys
130
+ || error instanceof errors.JWSSignatureVerificationFailed) {
131
+ return createInvalidTokenError("token signature invalid");
132
+ }
133
+ if (error instanceof errors.JWKSInvalid) {
134
+ return createInvalidTokenError("invalid JWKS document");
135
+ }
136
+ if (error instanceof errors.JWKSTimeout) {
137
+ return createInvalidTokenError("timed out loading JWKS");
138
+ }
139
+ if (error instanceof Error) {
140
+ return createInvalidTokenError(error.message);
141
+ }
142
+ return createInvalidTokenError("token verification failed");
143
+ }
144
+ async function loadJwks(jwksUrl, fetchImplementation) {
145
+ const response = await fetchImplementation(jwksUrl, {
146
+ headers: {
147
+ Accept: "application/json",
148
+ },
149
+ });
150
+ if (!response.ok) {
151
+ throw createInvalidTokenError(`unable to load JWKS (${response.status})`);
152
+ }
153
+ const payload = (await response.json());
154
+ if (!isObjectRecord(payload) || !Array.isArray(payload.keys)) {
155
+ throw createInvalidTokenError("invalid JWKS document");
156
+ }
157
+ return payload;
158
+ }
159
+ function resolveAlgorithm(token, allowedAlgorithms) {
160
+ const header = decodeProtectedHeader(token);
161
+ const alg = header.alg;
162
+ if (hasCriticalHeaderClaims(header)) {
163
+ throw createInvalidTokenError("unsupported critical token claims");
164
+ }
165
+ if (typeof alg !== "string"
166
+ || alg === "none"
167
+ || alg.startsWith("HS")
168
+ || !allowedAlgorithms.includes(alg)) {
169
+ throw createInvalidTokenError("unsupported token algorithm");
170
+ }
171
+ return alg;
172
+ }
173
+ function hasCriticalHeaderClaims(header) {
174
+ return Array.isArray(header.crit) && header.crit.length > 0;
175
+ }
176
+ function isVerificationCandidate(key, alg, kid) {
177
+ if (kid !== undefined && key.kid !== kid) {
178
+ return false;
179
+ }
180
+ if (typeof key.alg === "string" && key.alg !== alg) {
181
+ return false;
182
+ }
183
+ if (typeof key.use === "string" && key.use !== "sig") {
184
+ return false;
185
+ }
186
+ if (Array.isArray(key.key_ops) && !key.key_ops.includes("verify")) {
187
+ return false;
188
+ }
189
+ return true;
190
+ }
191
+ function shouldContinueWithNextKey(error) {
192
+ return error instanceof errors.JWSSignatureVerificationFailed;
193
+ }
194
+ async function verifyJwtAgainstJwks(input) {
195
+ const protectedHeader = decodeProtectedHeader(input.token);
196
+ const kid = typeof protectedHeader.kid === "string" ? protectedHeader.kid : undefined;
197
+ const candidateKeys = input.jwks.keys.filter((key) => isVerificationCandidate(key, input.alg, kid));
198
+ if (candidateKeys.length === 0) {
199
+ throw createInvalidTokenError("token signature invalid");
200
+ }
201
+ let lastSignatureError;
202
+ for (const candidate of candidateKeys) {
203
+ try {
204
+ const key = await importJWK(candidate, input.alg);
205
+ return await jwtVerify(input.token, key, {
206
+ algorithms: [input.alg],
207
+ issuer: [...input.authorizationServers],
208
+ clockTolerance: input.clockSkewSeconds,
209
+ });
210
+ }
211
+ catch (error) {
212
+ if (shouldContinueWithNextKey(error)) {
213
+ lastSignatureError = error;
214
+ continue;
215
+ }
216
+ throw error;
217
+ }
218
+ }
219
+ throw lastSignatureError ?? createInvalidTokenError("token signature invalid");
220
+ }
221
+ export function createJwksTokenVerifier(options) {
222
+ const jwksUrl = toUrl(options.jwksUrl, "jwksUrl");
223
+ const clockSkewSeconds = options.clockSkewSeconds ?? 30;
224
+ const allowedAlgorithms = options.allowedAlgorithms ?? DEFAULT_ALLOWED_ALGORITHMS;
225
+ const fetchImplementation = options.fetch ?? globalThis.fetch;
226
+ if (typeof fetchImplementation !== "function") {
227
+ throw new Error("fetch is not available; pass options.fetch explicitly");
228
+ }
229
+ return {
230
+ async verify(input) {
231
+ const expectedResource = canonicalizeResourceIndicator(input.resource);
232
+ const algorithm = resolveAlgorithm(input.token, allowedAlgorithms);
233
+ try {
234
+ const jwks = await loadJwks(jwksUrl, fetchImplementation);
235
+ const verified = await verifyJwtAgainstJwks({
236
+ token: input.token,
237
+ jwks,
238
+ alg: algorithm,
239
+ authorizationServers: input.authorizationServers,
240
+ clockSkewSeconds,
241
+ });
242
+ const audience = normalizeVerifiedAudience(verified.payload.aud, expectedResource);
243
+ const accessToken = toVerifiedAccessToken(input.token, verified.payload, audience);
244
+ if (input.requiredScopes.length > 0
245
+ && !accessToken.scopes.some((scope) => input.requiredScopes.includes(scope))) {
246
+ throw createTokenVerificationError({
247
+ error: "insufficient_scope",
248
+ errorDescription: "insufficient scope",
249
+ scope: [...input.requiredScopes],
250
+ });
251
+ }
252
+ return accessToken;
253
+ }
254
+ catch (error) {
255
+ throw normalizeVerificationError(error);
256
+ }
257
+ },
258
+ };
259
+ }
@@ -0,0 +1,22 @@
1
+ const ignoredImplicitGrantOptions = {
2
+ client: {
3
+ mode: "static",
4
+ clientId: "client-id",
5
+ // @ts-expect-error implicit response types are not configurable via the public API
6
+ responseType: "token",
7
+ },
8
+ browser: {
9
+ openBrowser: async () => { },
10
+ },
11
+ };
12
+ const ignoredPasswordGrantOptions = {
13
+ client: {
14
+ mode: "dynamic",
15
+ // @ts-expect-error password grants are not configurable via the public API
16
+ grantType: "password",
17
+ },
18
+ browser: {
19
+ openBrowser: async () => { },
20
+ },
21
+ };
22
+ export {};
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "mcp-oauth",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "tsc"
15
+ },
16
+ "dependencies": {
17
+ "auth-store": "*",
18
+ "jose": "^6.1.2"
19
+ },
20
+ "devDependencies": {
21
+ "tiny-oauth-test-server": "*"
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/poe-platform/poe-code.git",
29
+ "directory": "packages/mcp-oauth"
30
+ }
31
+ }
@@ -0,0 +1,4 @@
1
+
2
+ > tiny-mcp-client@0.1.0 build
3
+ > tsc
4
+