diff --git a/apps/web/src/app/(profile)/[username]/agents/[uid]/page.tsx b/apps/web/src/app/(profile)/[username]/agents/[uid]/page.tsx
index 961dd7b..9c5f4a2 100644
--- a/apps/web/src/app/(profile)/[username]/agents/[uid]/page.tsx
+++ b/apps/web/src/app/(profile)/[username]/agents/[uid]/page.tsx
@@ -2,6 +2,7 @@
import { Badge } from '@tpmjs/ui/Badge/Badge';
import { Button } from '@tpmjs/ui/Button/Button';
+import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
import { Icon } from '@tpmjs/ui/Icon/Icon';
import Link from 'next/link';
import { notFound, useParams } from 'next/navigation';
@@ -71,6 +72,113 @@ interface PublicAgent {
} | null;
}
+function AgentApiSection({
+ agentId,
+ provider,
+ isOwner,
+}: {
+ agentId: string;
+ provider: string;
+ isOwner: boolean;
+}) {
+ const [showExample, setShowExample] = useState(false);
+
+ const baseUrl = typeof window !== 'undefined' ? window.location.origin : 'https://tpmjs.com';
+ const apiUrl = `${baseUrl}/api/agents/${agentId}/conversation`;
+
+ const apiExampleSnippet = `// Create a conversation and send a message
+const createConvo = await fetch("${apiUrl}", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": "Bearer YOUR_TPMJS_API_KEY"
+ },
+ body: JSON.stringify({
+ name: "My Conversation"
+ })
+});
+const { data: { conversation } } = await createConvo.json();
+
+// Send a message (include providerApiKey for non-owners)
+const response = await fetch(\`${apiUrl}/\${conversation.id}\`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": "Bearer YOUR_TPMJS_API_KEY"
+ },
+ body: JSON.stringify({
+ message: "Hello!",
+ providerApiKey: "YOUR_${provider.toUpperCase()}_API_KEY", // Required for non-owners
+ env: {
+ // Your env vars for any tools the agent uses
+ "SOME_API_KEY": "your-key-here"
+ }
+ })
+});`;
+
+ return (
+
+
+
+
+
+
+
+ Conversation API
+
+
+
+
+
+
+ {/* Note for non-owners */}
+ {!isOwner && (
+
+
+
+ You'll need to provide your own {provider} API key via the{' '}
+ providerApiKey field,
+ plus any tool credentials via the{' '}
+ env parameter.
+
+
+ )}
+
+
+
setShowExample(!showExample)}
+ className="flex items-center gap-2 text-sm text-primary hover:text-primary/80 transition-colors"
+ >
+
+ Show API usage example
+
+
+ {showExample && (
+
+
+
+ )}
+
+
+
+
+ Learn more about the Agent Conversation API
+
+
+
+ );
+}
+
export default function PrettyAgentDetailPage(): React.ReactElement {
const params = useParams();
const rawUsername = params.username as string;
@@ -154,14 +262,12 @@ export default function PrettyAgentDetailPage(): React.ReactElement {
- {isOwner && (
-
-
-
- Chat
-
-
- )}
+
+
+
+ Chat
+
+
@@ -185,10 +291,8 @@ export default function PrettyAgentDetailPage(): React.ReactElement {
Temperature: {agent.temperature}
- {/* Fork CTA for non-owners */}
- {!isOwner && (
-
- )}
+ {/* API Access - Available to everyone (non-owners must provide their own credentials) */}
+
{/* System Prompt */}
{agent.systemPrompt && (
diff --git a/apps/web/src/app/(profile)/[username]/collections/[slug]/page.tsx b/apps/web/src/app/(profile)/[username]/collections/[slug]/page.tsx
index 39eeeef..2e10129 100644
--- a/apps/web/src/app/(profile)/[username]/collections/[slug]/page.tsx
+++ b/apps/web/src/app/(profile)/[username]/collections/[slug]/page.tsx
@@ -74,9 +74,18 @@ interface PublicCollection {
useCasesGeneratedAt: string | null;
}
-function McpUrlSection({ username, slug }: { username: string; slug: string }) {
+function McpUrlSection({
+ username,
+ slug,
+ isOwner,
+}: {
+ username: string;
+ slug: string;
+ isOwner: boolean;
+}) {
const [copiedUrl, setCopiedUrl] = useState<'http' | 'sse' | null>(null);
const [showConfig, setShowConfig] = useState(false);
+ const [showApiExample, setShowApiExample] = useState(false);
const baseUrl = typeof window !== 'undefined' ? window.location.origin : 'https://tpmjs.com';
const httpUrl = `${baseUrl}/api/mcp/${username}/${slug}/http`;
@@ -100,6 +109,28 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
}
}`;
+ const apiExampleSnippet = `// Call a tool with your own credentials
+const response = await fetch("${httpUrl}", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Authorization": "Bearer YOUR_TPMJS_API_KEY"
+ },
+ body: JSON.stringify({
+ jsonrpc: "2.0",
+ method: "tools/call",
+ params: {
+ name: "tool-name",
+ arguments: { /* tool args */ },
+ env: {
+ // Your env vars for the tools
+ "API_KEY": "your-key-here"
+ }
+ },
+ id: 1
+ })
+});`;
+
return (
@@ -159,8 +190,20 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
+ {/* Note for non-owners */}
+ {!isOwner && (
+
+
+
+ You'll need to provide your own API keys for any tools that require them. Pass
+ credentials via the env{' '}
+ parameter in your API calls.
+
+
+ )}
+
{/* Config snippet toggle */}
-
+
setShowConfig(!showConfig)}
@@ -175,6 +218,25 @@ function McpUrlSection({ username, slug }: { username: string; slug: string }) {
)}
+
+ {!isOwner && (
+ <>
+
setShowApiExample(!showApiExample)}
+ className="flex items-center gap-2 text-sm text-primary hover:text-primary/80 transition-colors"
+ >
+
+ Show API usage example
+
+
+ {showApiExample && (
+
+
+
+ )}
+ >
+ )}
@@ -310,17 +372,8 @@ export default function PrettyCollectionDetailPage(): React.ReactElement {
)}
- {/* MCP Server URLs - Only shown for owner */}
- {isOwner ? (
-
- ) : (
-
- )}
+ {/* MCP Server URLs - Available to everyone (non-owners must provide their own credentials) */}
+
{/* Tools */}
{collection.tools.length > 0 ? (