Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,674 changes: 766 additions & 1,908 deletions autonomous-agent-snowflake-wif/package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions autonomous-agent-snowflake-wif/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
"@earendil-works/pi-agent-core": "^0.74.0",
"@earendil-works/pi-ai": "^0.74.0",
"@keycardai/a2a": "^0.2.0",
"@keycardai/mcp": "^0.12.1",
"@keycardai/mcp": "^2.0.0",
"@keycardai/oauth": "^0.6.0",
"@modelcontextprotocol/sdk": "^1.15.0",
"@modelcontextprotocol/client": "^2.0.0",
"express": "^5.0.0",
"snowflake-sdk": "^2.4.1",
"typebox": "^1.1.24",
Expand Down
8 changes: 4 additions & 4 deletions autonomous-agent-snowflake-wif/src/mcpClient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import {
Client,
StreamableHTTPClientTransport,
extractResourceMetadataUrl,
discoverOAuthProtectedResourceMetadata,
} from "@modelcontextprotocol/sdk/client/auth.js";
import type { FetchLike } from "@modelcontextprotocol/sdk/shared/transport.js";
} from "@modelcontextprotocol/client";
import type { FetchLike } from "@modelcontextprotocol/client";
import type { KeycardTokenProvider } from "./tokenProvider.js";

/**
Expand Down
2 changes: 1 addition & 1 deletion autonomous-agent-snowflake-wif/src/tools.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
import type { Client } from "@modelcontextprotocol/client";
import type { AgentTool, AgentToolResult } from "@earendil-works/pi-agent-core";
import { Type, type TSchema } from "typebox";

Expand Down
6 changes: 3 additions & 3 deletions mcp-brokered-credentials-python/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"Set it in .env or run via `keycard run -- uvicorn main:app`."
)

from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer
from keycardai.mcp.server.auth import AuthProvider
from keycardai.starlette import KeycardAuthBackend, keycard_on_error
from keycardai.starlette.routers.metadata import auth_metadata_mount
Expand All @@ -47,7 +47,7 @@
mcp_server_url=SERVER_URL,
)

mcp = FastMCP(SERVER_NAME, streamable_http_path="/")
mcp = MCPServer(SERVER_NAME)
register_search_tool(mcp, auth_provider)
register_execute_tool(mcp, auth_provider)

Expand All @@ -73,7 +73,7 @@ async def lifespan(app):
routes=[
Route("/healthz", healthz, methods=["GET"]),
auth_metadata_mount(auth_provider.issuer),
Mount("/mcp", app=mcp.streamable_http_app(), middleware=[strict_auth]),
Mount("/mcp", app=mcp.streamable_http_app(streamable_http_path="/"), middleware=[strict_auth]),
],
lifespan=lifespan,
)
Expand Down
7 changes: 1 addition & 6 deletions mcp-brokered-credentials-python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ name = "mcp-brokered-credentials-python"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
"keycardai-mcp>=0.15.0",
# Pinned below mcp 2.0 deliberately. keycardai-mcp 0.26.0 declares an
# unbounded "mcp>=1.13.1", so a fresh resolve pulls mcp 2.0.0, which removed
# mcp.server.fastmcp and makes keycardai-mcp fail to import. Drop this pin
# once a keycardai-mcp release that targets mcp 2.0 is published.
"mcp<2.0",
"keycardai-mcp>=2,<3",
"httpx>=0.27.0",
"uvicorn>=0.29.0",
"starlette>=0.27.0",
Expand Down
4 changes: 2 additions & 2 deletions mcp-brokered-credentials-python/tools/execute.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import json
from typing import Any

from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from keycardai.mcp.server.auth import AuthProvider

from upstream import linear_client_for_user


def register_execute_tool(mcp: FastMCP, auth_provider: AuthProvider) -> None:
def register_execute_tool(mcp: MCPServer, auth_provider: AuthProvider) -> None:
@mcp.tool(
description=(
"Execute a tool on the upstream Linear MCP server. "
Expand Down
4 changes: 2 additions & 2 deletions mcp-brokered-credentials-python/tools/search.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import json
import re

from mcp.server.fastmcp import Context, FastMCP
from mcp.server.mcpserver import Context, MCPServer
from keycardai.mcp.server.auth import AuthProvider

from upstream import linear_client_for_user


def register_search_tool(mcp: FastMCP, auth_provider: AuthProvider) -> None:
def register_search_tool(mcp: MCPServer, auth_provider: AuthProvider) -> None:
@mcp.tool(
description=(
"Search the upstream Linear MCP server's tool catalog by regex. "
Expand Down
2 changes: 1 addition & 1 deletion mcp-brokered-credentials-python/upstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client
from mcp.server.fastmcp import Context
from mcp.server.mcpserver import Context
from keycardai.mcp.server.auth import AuthProvider
from keycardai.oauth.server import AccessContext, exchange_tokens_for_resources

Expand Down
436 changes: 234 additions & 202 deletions mcp-brokered-credentials-python/uv.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion mcp-brokered-credentials-typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A small MCP **proxy** server that demonstrates Keycard as a credential broker. I

It also demonstrates **vault-brokered application credentials**: the proxy's own Keycard `client_id` / `client_secret` are stored as zone-vault resources and injected into the process by `keycard run`, never written to disk. When deployed to a cloud platform (Fly.io, EKS), the proxy automatically discovers workload-identity credentials from the environment instead — no static secrets needed.

Built on [`@keycardai/mcp`](https://www.npmjs.com/package/@keycardai/mcp), the official `@modelcontextprotocol/sdk`, and Express 5 over the Streamable HTTP transport.
Built on [`@keycardai/mcp`](https://www.npmjs.com/package/@keycardai/mcp), the official MCP v2 SDK (`@modelcontextprotocol/server`), and Express 5 over the Streamable HTTP transport.

## How it works

Expand Down
Loading
Loading