Skip to content

Latest commit

 

History

History
332 lines (243 loc) · 11.4 KB

File metadata and controls

332 lines (243 loc) · 11.4 KB

Use Dynamic Feed from your agent framework

Dynamic Feed is a keyless remote MCP server. Point any MCP-capable agent framework at https://dynamicfeed.ai/mcp and your agent gains 91 live, read-only tools (weather, hazards, CVEs, sanctions, economics, space weather, and more). No account, no API key, no local install. Every tool result comes back in an Ed25519-signed, provenance-stamped envelope you can verify offline, even against us.

What Where
MCP endpoint (streamable HTTP, keyless) https://dynamicfeed.ai/mcp
Discovery manifest https://dynamicfeed.ai/.well-known/mcp.json
REST fallback (no MCP client needed) POST https://dynamicfeed.ai/v1/batch
Verify a signed result https://github.com/dynamicfeed/df-verify

One note on every snippet below: Dynamic Feed itself needs no key. The model your agent runs on (OpenAI, Anthropic, and so on) is your own choice and uses your own key. Swap the model string for whatever you use.

30-second check (no SDK)

curl -sN https://dynamicfeed.ai/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-06-18' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

The server identifies itself as "Dynamic Feed". That is the whole handshake.

OpenAI Agents SDK

pip install openai-agents

import asyncio

from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp


async def main():
    # Keyless remote streamable-HTTP MCP server. No auth: just omit "headers".
    async with MCPServerStreamableHttp(
        name="Dynamic Feed",
        params={
            "url": "https://dynamicfeed.ai/mcp",
            # no "headers"/"auth" key => no authentication is sent
            "timeout": 30,
        },
        cache_tools_list=True,  # remote servers add latency; cache the tool list
    ) as server:
        # List the tools the server exposes
        tools = await server.list_tools()
        print(f"{len(tools)} tools available:", [t.name for t in tools[:5]], "...")

        # Wire the MCP server into an Agent (needs OPENAI_API_KEY in env for the LLM)
        agent = Agent(
            name="Assistant",
            instructions="Use the Dynamic Feed MCP tools to answer questions.",
            mcp_servers=[server],
        )

        # The Agents SDK auto-calls list_tools() and invokes tools as needed.
        result = await Runner.run(
            starting_agent=agent,
            input="What is the current weather in Sydney? Use the current_weather tool.",
        )
        print(result.final_output)


if __name__ == "__main__":
    asyncio.run(main())

LangGraph / LangChain

pip install langchain-mcp-adapters langgraph "langchain[anthropic]"

import asyncio

from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent


async def main():
    # Connect to the KEYLESS remote streamable-HTTP MCP server.
    # No auth: just omit any "headers"/"auth" keys.
    client = MultiServerMCPClient(
        {
            "dynamicfeed": {
                "transport": "streamable_http",   # underscore form is required
                "url": "https://dynamicfeed.ai/mcp",
            },
        }
    )

    # Load all Dynamic Feed tools as LangChain tools (async; does an MCP tools/list).
    tools = await client.get_tools()
    print(f"Loaded {len(tools)} tools:", [t.name for t in tools][:5], "...")

    # Bind the tools into a LangGraph ReAct agent.
    # create_react_agent accepts a "provider:model" string and binds tools internally.
    # (The model string requires ANTHROPIC_API_KEY, which is for the LLM, NOT the MCP server.)
    agent = create_react_agent("anthropic:claude-sonnet-4-5", tools)

    result = await agent.ainvoke(
        {"messages": [{"role": "user", "content": "What's the current weather in Sydney?"}]}
    )
    print(result["messages"][-1].content)


if __name__ == "__main__":
    asyncio.run(main())

CrewAI

pip install "crewai-tools[mcp]" crewai

"""
Connect CrewAI to the KEYLESS remote Dynamic Feed MCP server (streamable HTTP).
No API key, no auth headers, no local install of the server.

Install:  pip install "crewai-tools[mcp]"
"""

from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter

# Remote streamable-HTTP MCP server. NO auth -> just url + transport, no headers.
server_params = {
    "url": "https://dynamicfeed.ai/mcp",
    "transport": "streamable-http",
}

# Context manager opens the connection and auto-closes it on exit.
with MCPServerAdapter(server_params) as tools:
    # 1) List the tools the server exposes.
    print(f"Available tools ({len(tools)}):", [t.name for t in tools])

    # 2) Give the tools to a CrewAI Agent.
    agent = Agent(
        role="Live Data Analyst",
        goal="Answer questions using fresh, signed data from Dynamic Feed",
        backstory="You query the Dynamic Feed MCP tools for real-world data.",
        tools=tools,            # all MCP tools, ready to use
        verbose=True,
    )

    # 3) One example tool call: current weather for Sydney.
    task = Task(
        description="Use the current_weather tool to get the current weather in Sydney, Australia.",
        expected_output="A short summary of Sydney's current weather.",
        agent=agent,
    )

    crew = Crew(agents=[agent], tasks=[task], process=Process.sequential, verbose=True)
    result = crew.kickoff()
    print(result)

Microsoft AutoGen

pip install -U autogen-agentchat "autogen-ext[openai,mcp]"

import asyncio

from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.tools.mcp import StreamableHttpServerParams, mcp_server_tools


async def main() -> None:
    # No-auth remote MCP server: just give the URL, do NOT set headers.
    server_params = StreamableHttpServerParams(
        url="https://dynamicfeed.ai/mcp",
        timeout=30.0,            # regular HTTP ops (seconds)
        sse_read_timeout=300.0,  # streamed-read timeout (seconds)
        terminate_on_close=True,
    )

    # Discover ALL tools on the server (returns a list of tool adapters,
    # one per remote tool).
    tools = await mcp_server_tools(server_params)
    print(f"Loaded {len(tools)} tools:", [t.name for t in tools][:5], "...")

    # Requires OPENAI_API_KEY in the environment.
    model_client = OpenAIChatCompletionClient(model="gpt-4o")
    agent = AssistantAgent(
        name="dynamicfeed_agent",
        model_client=model_client,
        tools=tools,  # attach every MCP tool to the agent
        system_message="You are a helpful assistant. Use the tools when useful.",
        reflect_on_tool_use=True,
    )

    # One example tool call driven by the model (calls current_weather for Sydney).
    result = await agent.run(task="What is the current weather in Sydney? Use current_weather.")
    print(result.messages[-1].content)

    await model_client.close()


if __name__ == "__main__":
    asyncio.run(main())

Pydantic AI

pip install pydantic-ai

import asyncio

from pydantic_ai import Agent
from pydantic_ai.mcp import MCPToolset

# Connect to the KEYLESS remote streamable-HTTP MCP server (no auth, no local install).
# In Pydantic AI v2.x, MCPToolset auto-detects Streamable HTTP from an http(s) URL
# (SSE is only used if the URL path ends in /sse). Do NOT pass auth/headers - keyless.
toolset = MCPToolset("https://dynamicfeed.ai/mcp")

# Attach the toolset to an agent; the model discovers all remote tools automatically.
agent = Agent("openai:gpt-4o", toolsets=[toolset])


async def main():
    # 1) List the tools the remote server exposes via the underlying FastMCP client.
    async with toolset.client:
        tools = await toolset.client.list_tools()
        print("tools:", [t.name for t in tools])  # e.g. current_weather, earthquakes, ...

    # 2) Let the agent call a tool. `async with agent:` opens/closes the MCP
    #    connection for all registered toolsets.
    async with agent:
        result = await agent.run("What is the current weather in Sydney?")
        print(result.output)


if __name__ == "__main__":
    asyncio.run(main())

Raw MCP SDK (no framework)

Tested live against https://dynamicfeed.ai/mcp (server "Dynamic Feed", 91 tools, signed result).

Python: pip install "mcp>=1.28"

import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

URL = "https://dynamicfeed.ai/mcp"  # keyless: no auth header, no token

async def main():
    async with streamablehttp_client(URL) as (read, write, _get_session_id):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            print("tools:", [t.name for t in tools.tools][:5], "...")
            result = await session.call_tool("current_weather", arguments={"city": "Sydney"})
            for block in result.content:
                if block.type == "text":
                    print(block.text)   # Ed25519-signed, provenance-stamped JSON

asyncio.run(main())

TypeScript / Node: npm i @modelcontextprotocol/sdk

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const client = new Client({ name: "df-client", version: "1.0.0" });

// No auth: construct the transport with just the URL.
const transport = new StreamableHTTPClientTransport(new URL("https://dynamicfeed.ai/mcp"));
await client.connect(transport);

const { tools } = await client.listTools();
console.log("tools:", tools.map(t => t.name));

const result = await client.callTool({ name: "current_weather", arguments: { city: "Sydney" } });
console.log(result.content);   // Ed25519-signed, provenance-stamped

await client.close();

No MCP? Use plain REST

Every tool is callable as JSON, and the whole response is Ed25519-signed.

curl -s https://dynamicfeed.ai/v1/batch \
  -H 'Content-Type: application/json' \
  -d '{"calls":[{"tool":"current_weather","args":{"city":"Sydney"}}]}'

Single fact by GET: https://dynamicfeed.ai/v1/facts?tool=current_weather&city=Sydney. Discover every tool: POST {} to /v1/batch, or fetch https://dynamicfeed.ai/tools.json.

Verify before you act

The point of Dynamic Feed is that an agent can prove the data before it acts. Every result carries a signature. Check it independently with the published verifiers (no runtime trust in us beyond fetching the public key):

Python: pip install dynamicfeed-verify

from dynamicfeed_verify import verify

result = verify(signed_response)      # the dict a tool returned
if not result["ok"]:
    raise RuntimeError(f"unverified data, refusing to act: {result['error']}")

JavaScript: npm i @dynamicfeed/verify

import { verify } from '@dynamicfeed/verify';

const { ok, error } = await verify(rawResponseText);
if (!ok) throw new Error(`unverified data: ${error}`);

Public keys live at https://dynamicfeed.ai/.well-known/keys . Full spec and reference verifiers in Python, JavaScript, C# and Rust: https://github.com/dynamicfeed/df-verify

Links